001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_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    }