001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/ogcwebservices/wpvs/WFSInvoker.java $ 002 /*---------------------------------------------------------------------------- 003 This file is part of deegree, http://deegree.org/ 004 Copyright (C) 2001-2009 by: 005 Department of Geography, University of Bonn 006 and 007 lat/lon GmbH 008 009 This library is free software; you can redistribute it and/or modify it under 010 the terms of the GNU Lesser General Public License as published by the Free 011 Software Foundation; either version 2.1 of the License, or (at your option) 012 any later version. 013 This library is distributed in the hope that it will be useful, but WITHOUT 014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 015 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 016 details. 017 You should have received a copy of the GNU Lesser General Public License 018 along with this library; if not, write to the Free Software Foundation, Inc., 019 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 020 021 Contact information: 022 023 lat/lon GmbH 024 Aennchenstr. 19, 53177 Bonn 025 Germany 026 http://lat-lon.de/ 027 028 Department of Geography, University of Bonn 029 Prof. Dr. Klaus Greve 030 Postfach 1147, 53001 Bonn 031 Germany 032 http://www.geographie.uni-bonn.de/deegree/ 033 034 e-mail: info@deegree.org 035 ----------------------------------------------------------------------------*/ 036 037 package org.deegree.ogcwebservices.wpvs; 038 039 import java.io.StringReader; 040 import java.util.ArrayList; 041 import java.util.HashMap; 042 import java.util.Map; 043 import java.util.Set; 044 045 import org.deegree.datatypes.QualifiedName; 046 import org.deegree.datatypes.Types; 047 import org.deegree.framework.log.ILogger; 048 import org.deegree.framework.log.LoggerFactory; 049 import org.deegree.framework.util.CharsetUtils; 050 import org.deegree.framework.util.IDGenerator; 051 import org.deegree.framework.xml.XMLFragment; 052 import org.deegree.framework.xml.XMLTools; 053 import org.deegree.model.feature.Feature; 054 import org.deegree.model.feature.FeatureCollection; 055 import org.deegree.model.feature.FeatureProperty; 056 import org.deegree.model.feature.schema.FeatureType; 057 import org.deegree.model.feature.schema.PropertyType; 058 import org.deegree.model.filterencoding.ComplexFilter; 059 import org.deegree.model.filterencoding.FeatureFilter; 060 import org.deegree.model.filterencoding.FeatureId; 061 import org.deegree.model.filterencoding.Filter; 062 import org.deegree.model.spatialschema.GMLGeometryAdapter; 063 import org.deegree.ogcbase.PropertyPath; 064 import org.deegree.ogcwebservices.OGCWebService; 065 import org.deegree.ogcwebservices.OGCWebServiceException; 066 import org.deegree.ogcwebservices.wfs.operation.FeatureResult; 067 import org.deegree.ogcwebservices.wfs.operation.GetFeature; 068 import org.deegree.ogcwebservices.wpvs.configuration.AbstractDataSource; 069 import org.deegree.ogcwebservices.wpvs.configuration.LocalWFSDataSource; 070 import org.deegree.ogcwebservices.wpvs.j3d.DefaultSurface; 071 import org.deegree.ogcwebservices.wpvs.j3d.Object3DFactory; 072 import org.deegree.ogcwebservices.wpvs.j3d.PointsToPointListFactory; 073 import org.deegree.ogcwebservices.wpvs.j3d.TexturedSurface; 074 import org.deegree.ogcwebservices.wpvs.utils.ResolutionStripe; 075 import org.w3c.dom.Document; 076 077 /** 078 * Invoker for a Web Feature Service. 079 * 080 * @author <a href="mailto:taddei@lat-lon.de">Ugo Taddei</a> 081 * @author last edited by: $Author: mschneider $ 082 * 083 * $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18 Jun 2009) $ 084 * 085 */ 086 public class WFSInvoker extends GetViewServiceInvoker { 087 088 private static final ILogger LOG = LoggerFactory.getLogger( WFSInvoker.class ); 089 090 /* whether the returned data is a 3D object or data for the elevation model */ 091 private final boolean isElevationModelRequest; 092 093 private int id; 094 095 /** 096 * Creates a new instance of this class. 097 * 098 * @param owner 099 * the ResolutionStripe that calls this invoker 100 * @param id 101 * @param isElevationModelRequest 102 */ 103 public WFSInvoker( ResolutionStripe owner, int id, boolean isElevationModelRequest ) { 104 super( owner ); 105 this.id = id; 106 this.isElevationModelRequest = isElevationModelRequest; 107 } 108 109 @Override 110 public void invokeService( AbstractDataSource dataSource ) { 111 if ( !( dataSource instanceof LocalWFSDataSource ) ) { 112 LOG.logError( "The given AbstractDataSource is no WFSDataSource instance. It is needed for a WFSInvoker" ); 113 throw new RuntimeException( "DataSource should be a WFS-instance for a WFSInvoker" ); 114 } 115 OGCWebService service = null; 116 try { 117 service = dataSource.getOGCWebService(); 118 } catch ( OGCWebServiceException ogcwe ) { 119 LOG.logError( ogcwe.getMessage() ); 120 } 121 Object response = null; 122 try { 123 GetFeature getFeature = createGetFeatureRequest( (LocalWFSDataSource) dataSource ); 124 if ( service != null ) { 125 response = service.doService( getFeature ); 126 } else { 127 LOG.logError( "The (WFS) service was null, therefore no response was given" ); 128 } 129 } catch ( OGCWebServiceException ogcwse ) { 130 if ( !Thread.currentThread().isInterrupted() ) { 131 LOG.logError( "Exception while performing WFS-GetFeature: ", ogcwse ); 132 } 133 return; 134 } 135 136 if ( response != null && response instanceof FeatureResult ) { 137 FeatureCollection result = (FeatureCollection) ( (FeatureResult) response ).getResponse(); 138 if ( result != null ) { 139 if ( isElevationModelRequest ) { 140 PointsToPointListFactory ptpFac = new PointsToPointListFactory(); 141 resolutionStripe.setElevationModelFromMeassurePoints( ptpFac.createFromFeatureCollection( result ) ); 142 } else { 143 Object3DFactory o3DFactory = new Object3DFactory(); 144 Map<String, TexturedSurface> textureMap = new HashMap<String, TexturedSurface>( result.size() * 10 ); 145 for ( int i = 0; i < result.size(); ++i ) { 146 Feature feature = result.getFeature( i ); 147 createSurfaces( o3DFactory, feature, textureMap ); 148 } 149 if ( textureMap.size() > 0 ) { 150 Set<String> keys = textureMap.keySet(); 151 int count = 0; 152 int total = textureMap.size(); 153 for ( String key : keys ) { 154 if ( key != null ) { 155 TexturedSurface surf = textureMap.get( key ); 156 if ( surf != null ) { 157 if ( LOG.isDebug() ) { 158 LOG.logDebug( "Adding textured surface (" + ( count++ ) + " of " + total 159 + "): " + key ); 160 } 161 surf.compile(); 162 resolutionStripe.addFeature( id + "_" + surf.getDefaultSurfaceID(), surf ); 163 } 164 } 165 166 } 167 } 168 } 169 170 } 171 } else { 172 LOG.logError( "ERROR while invoking wfs-datasource: " + dataSource.getName() 173 + " the result was no WFS-response or no FeatureResult instance" ); 174 } 175 176 } 177 178 /** 179 * This method recursively constructs all the surfaces contained in the given feature. If the 180 * Feature contains a PropertyType of {@link Types#FEATURE} this Feature will also be traversed, 181 * if it contains a {@link Types#GEOMETRY} a {@link DefaultSurface} will be created. 182 * 183 * @param o3DFactory 184 * the Factory to create the defaultservice 185 * @param feature 186 * the feature to traverse. 187 */ 188 private void createSurfaces( Object3DFactory o3DFactory, Feature feature, Map<String, TexturedSurface> textureMap ) { 189 190 FeatureType ft = feature.getFeatureType(); 191 PropertyType[] propertyTypes = ft.getProperties(); 192 for ( PropertyType pt : propertyTypes ) { 193 if ( pt.getType() == Types.FEATURE ) { 194 FeatureProperty[] fp = feature.getProperties( pt.getName() ); 195 if ( fp != null ) { 196 for ( int i = 0; i < fp.length; i++ ) { 197 createSurfaces( o3DFactory, (Feature) fp[i].getValue(), textureMap ); 198 } 199 } 200 } else if ( pt.getType() == Types.GEOMETRY ) { 201 DefaultSurface ds = o3DFactory.createSurface( feature, textureMap ); 202 if ( ds != null ) { 203 ds.compile(); 204 resolutionStripe.addFeature( id + "_" + ds.getDefaultSurfaceID(), ds ); 205 } 206 } 207 } 208 } 209 210 /** 211 * Creates a new <code>GetFeature</code> object from an "XML-String" not nice. 212 * 213 * @param dataSource 214 * the datasource containing service data 215 * @return a new GetFeature request 216 */ 217 private GetFeature createGetFeatureRequest( LocalWFSDataSource dataSource /* 218 * String id, 219 * Surface[] boxes 220 */) 221 throws OGCWebServiceException { 222 223 QualifiedName qn = dataSource.getName(); 224 225 StringBuilder sb = new StringBuilder( 5000 ); 226 sb.append( "<?xml version='1.0' encoding='" + CharsetUtils.getSystemCharset() + "'?>" ); 227 sb.append( "<wfs:GetFeature xmlns:wfs='http://www.opengis.net/wfs' " ); 228 sb.append( "xmlns:ogc='http://www.opengis.net/ogc' " ); 229 sb.append( "xmlns:gml='http://www.opengis.net/gml' " ); 230 sb.append( "xmlns:" ).append( qn.getPrefix() ).append( '=' ); 231 sb.append( "'" ).append( qn.getNamespace() ).append( "' " ); 232 if ( dataSource.getMaxFeatures() > 0 ) { 233 sb.append( "maxFeatures='" ).append( dataSource.getMaxFeatures() ).append( "' " ); 234 } 235 236 if ( dataSource.getServiceType() == AbstractDataSource.LOCAL_WFS ) { 237 sb.append( "outputFormat='FEATURECOLLECTION'>" ); 238 } else { 239 sb.append( "outputFormat='text/xml; subtype=gml/3.1.1'>" ); 240 } 241 242 /** 243 * To make things a little clearer compare with this SQL-Statement: SELECT ( !texture )? 244 * geoProperty : * FROM qn.getLocalName() WHERE geoPoperty intersects with 245 * resolutionStripe.getSurface() AND FilterConditions. 246 */ 247 PropertyPath geoProperty = dataSource.getGeometryProperty(); 248 249 // FROM 250 sb.append( "<wfs:Query typeName='" ).append( qn.getPrefix() ).append( ":" ); 251 sb.append( qn.getLocalName() ).append( "'>" ); 252 253 // SELECT 254 /* 255 * if ( !isElevationModelRequest ) { sb.append( "<wfs:PropertyName>" ); sb.append( 256 * geoProperty.getAsString() ); sb.append( "</wfs:PropertyName>" ); } 257 */ 258 259 StringBuffer sbArea = GMLGeometryAdapter.exportAsEnvelope( resolutionStripe.getSurface().getEnvelope() ); 260 261 // WHERE 262 sb.append( "<ogc:Filter>" ); 263 264 // AND 265 Filter filter = dataSource.getFilter(); 266 if ( filter != null ) { 267 if ( filter instanceof ComplexFilter ) { 268 sb.append( "<ogc:And>" ); 269 sb.append( "<ogc:Intersects>" ); 270 sb.append( "<wfs:PropertyName>" ); 271 sb.append( geoProperty.getAsString() ); 272 sb.append( "</wfs:PropertyName>" ); 273 sb.append( sbArea ); 274 sb.append( "</ogc:Intersects>" ); 275 // add filter as defined in the layers datasource description 276 // to the filter expression 277 org.deegree.model.filterencoding.Operation op = ( (ComplexFilter) filter ).getOperation(); 278 sb.append( op.toXML() ).append( "</ogc:And>" ); 279 } else { 280 if ( filter instanceof FeatureFilter ) { 281 ArrayList<FeatureId> featureIds = ( (FeatureFilter) filter ).getFeatureIds(); 282 if ( featureIds.size() != 0 ) 283 sb.append( "<ogc:And>" ); 284 for ( FeatureId fid : featureIds ) { 285 sb.append( fid.toXML() ); 286 } 287 if ( featureIds.size() != 0 ) 288 sb.append( "</ogc:And>" ); 289 } 290 } 291 } else { 292 sb.append( "<ogc:Intersects>" ); 293 sb.append( "<wfs:PropertyName>" ); 294 sb.append( geoProperty.getAsString() ); 295 sb.append( "</wfs:PropertyName>" ); 296 sb.append( sbArea ); 297 sb.append( "</ogc:Intersects>" ); 298 } 299 300 sb.append( "</ogc:Filter></wfs:Query></wfs:GetFeature>" ); 301 302 Document doc; 303 try { 304 doc = XMLTools.parse( new StringReader( sb.toString() ) ); 305 } catch ( Exception e ) { 306 LOG.logError( e.getMessage(), e ); 307 throw new OGCWebServiceException( e.getMessage() ); 308 } 309 310 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) { 311 System.out.println( sb.toString() ); 312 XMLFragment d = new XMLFragment( doc.getDocumentElement() ); 313 LOG.logDebug( d.getAsPrettyString() ); 314 } 315 316 IDGenerator idg = IDGenerator.getInstance(); 317 return GetFeature.create( String.valueOf( idg.generateUniqueID() ), doc.getDocumentElement() ); 318 } 319 320 }