001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/ogcwebservices/wpvs/WFSInvoker.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2008 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.xml.XMLFragment;
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.OGCWebService;
070    import org.deegree.ogcwebservices.OGCWebServiceException;
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: rbezema $
086     * 
087     * $Revision: 12293 $, $Date: 2008-06-11 10:28:37 +0200 (Mi, 11 Jun 2008) $
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            OGCWebService service = null;
120            try {
121                service = dataSource.getOGCWebService();
122            } catch ( OGCWebServiceException ogcwe ) {
123                LOG.logError( ogcwe.getMessage() );
124            }
125            Object response = null;
126            try {
127                GetFeature getFeature = createGetFeatureRequest( (LocalWFSDataSource) dataSource );
128                if ( service != null ) {
129                    response = service.doService( getFeature );
130                } else {
131                    LOG.logError( "The (WFS) service was null, therefore no response was given" );
132                }
133            } catch ( OGCWebServiceException ogcwse ) {
134                if ( !Thread.currentThread().isInterrupted() ) {
135                    LOG.logError( "Exception while performing WFS-GetFeature: ", ogcwse );
136                }
137                return;
138            }
139    
140            if ( response != null && response instanceof FeatureResult ) {
141                FeatureCollection result = (FeatureCollection) ( (FeatureResult) response ).getResponse();
142                if ( result != null ) {
143                    if ( isElevationModelRequest ) {
144                        PointsToPointListFactory ptpFac = new PointsToPointListFactory();
145                        resolutionStripe.setElevationModelFromMeassurePoints( ptpFac.createFromFeatureCollection( result ) );
146                    } else {
147                        Object3DFactory o3DFactory = new Object3DFactory();
148                        for ( int i = 0; i < result.size(); ++i ) {
149                            Feature feature = result.getFeature( i );
150                            createSurfaces( o3DFactory, feature );
151                        }
152                    }
153                }
154            } else {
155                LOG.logError( "ERROR while invoking wfs-datasource: " + dataSource.getName()
156                              + " the result was no WFS-response or no FeatureResult instance" );
157            }
158    
159        }
160    
161        /**
162         * This method recursively constructs all the surfaces contained in the given feature. If the
163         * Feature contains a PropertyType of {@link Types#FEATURE} this Feature will also be traversed,
164         * if it contains a {@link Types#GEOMETRY} a {@link DefaultSurface} will be created.
165         * 
166         * @param o3DFactory
167         *            the Factory to create the defaultservice
168         * @param feature
169         *            the feature to traverse.
170         */
171        private void createSurfaces( Object3DFactory o3DFactory, Feature feature ) {
172    
173            FeatureType ft = feature.getFeatureType();
174            PropertyType[] propertyTypes = ft.getProperties();
175            for ( PropertyType pt : propertyTypes ) {
176                if ( pt.getType() == Types.FEATURE ) {
177                    FeatureProperty[] fp = feature.getProperties( pt.getName() );
178                    if ( fp != null ) {
179                        for ( int i = 0; i < fp.length; i++ ) {
180                            createSurfaces( o3DFactory, (Feature) fp[i].getValue() );
181                        }
182                    }
183                } else if ( pt.getType() == Types.GEOMETRY ) {
184                    DefaultSurface ds = o3DFactory.createSurface( feature );
185                    if ( ds != null ) {
186                        resolutionStripe.addFeature( id + "_" + ds.getDefaultSurfaceID(), ds );
187                    }
188                }
189            }
190        }
191    
192        /**
193         * Creates a new <code>GetFeature</code> object from an "XML-String" not nice.
194         * 
195         * @param ds
196         *            the datasource containig service data
197         * @param id
198         *            the request id
199         * @return a new GetFeature request
200         * @throws GeometryException
201         * @throws OGCWebServiceException
202         * @throws Exception
203         */
204        private GetFeature createGetFeatureRequest( LocalWFSDataSource dataSource /*
205                                                                                     * String id,
206                                                                                     * Surface[] boxes
207                                                                                     */)
208                                throws OGCWebServiceException {
209    
210            QualifiedName qn = dataSource.getName();
211    
212            StringBuilder sb = new StringBuilder( 5000 );
213            sb.append( "<?xml version='1.0' encoding='" + CharsetUtils.getSystemCharset() + "'?>" );
214            sb.append( "<wfs:GetFeature xmlns:wfs='http://www.opengis.net/wfs' " );
215            sb.append( "xmlns:ogc='http://www.opengis.net/ogc' " );
216            sb.append( "xmlns:gml='http://www.opengis.net/gml' " );
217            sb.append( "xmlns:" ).append( qn.getPrefix() ).append( '=' );
218            sb.append( "'" ).append( qn.getNamespace() ).append( "' " );
219            if ( dataSource.getMaxFeatures() > 0 ) {
220                sb.append( "maxFeatures='" ).append( dataSource.getMaxFeatures() ).append( "' " );
221            }
222    
223            if ( dataSource.getServiceType() == AbstractDataSource.LOCAL_WFS ) {
224                sb.append( "outputFormat='FEATURECOLLECTION'>" );
225            } else {
226                sb.append( "outputFormat='text/xml; subtype=gml/3.1.1'>" );
227            }
228    
229            /**
230             * To make things a little clearer compare with this SQL-Statement: SELECT ( !texture )?
231             * geoProperty : * FROM qn.getLocalName() WHERE geoPoperty intersects with
232             * resolutionStripe.getSurface() AND FilterConditions.
233             */
234            PropertyPath geoProperty = dataSource.getGeometryProperty();
235    
236            // FROM
237            sb.append( "<wfs:Query typeName='" ).append( qn.getPrefix() ).append( ":" );
238            sb.append( qn.getLocalName() ).append( "'>" );
239    
240            // SELECT
241            /*
242             * if ( !isElevationModelRequest ) { sb.append( "<wfs:PropertyName>" ); sb.append(
243             * geoProperty.getAsString() ); sb.append( "</wfs:PropertyName>" ); }
244             */
245    
246            StringBuffer sbArea = GMLGeometryAdapter.exportAsEnvelope( resolutionStripe.getSurface().getEnvelope() );
247    
248            // WHERE
249            sb.append( "<ogc:Filter>" );
250    
251            // AND
252            Filter filter = dataSource.getFilter();
253            if ( filter != null ) {
254                if ( filter instanceof ComplexFilter ) {
255                    sb.append( "<ogc:And>" );
256                    sb.append( "<ogc:Intersects>" );
257                    sb.append( "<wfs:PropertyName>" );
258                    sb.append( geoProperty.getAsString() );
259                    sb.append( "</wfs:PropertyName>" );
260                    sb.append( sbArea );
261                    sb.append( "</ogc:Intersects>" );
262                    // add filter as defined in the layers datasource description
263                    // to the filter expression
264                    org.deegree.model.filterencoding.Operation op = ( (ComplexFilter) filter ).getOperation();
265                    sb.append( op.toXML() ).append( "</ogc:And>" );
266                } else {
267                    if ( filter instanceof FeatureFilter ) {
268                        ArrayList<FeatureId> featureIds = ( (FeatureFilter) filter ).getFeatureIds();
269                        if ( featureIds.size() != 0 )
270                            sb.append( "<ogc:And>" );
271                        for ( FeatureId fid : featureIds ) {
272                            sb.append( fid.toXML() );
273                        }
274                        if ( featureIds.size() != 0 )
275                            sb.append( "</ogc:And>" );
276                    }
277                }
278            } else {
279                sb.append( "<ogc:Intersects>" );
280                sb.append( "<wfs:PropertyName>" );
281                sb.append( geoProperty.getAsString() );
282                sb.append( "</wfs:PropertyName>" );
283                sb.append( sbArea );
284                sb.append( "</ogc:Intersects>" );
285            }
286    
287            sb.append( "</ogc:Filter></wfs:Query></wfs:GetFeature>" );
288    
289            Document doc;
290            try {
291                doc = XMLTools.parse( new StringReader( sb.toString() ) );
292            } catch ( Exception e ) {
293                LOG.logError( e.getMessage(), e );
294                throw new OGCWebServiceException( e.getMessage() );
295            }
296    
297            if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
298                XMLFragment d = new XMLFragment( doc.getDocumentElement() );
299                LOG.logDebug( d.getAsPrettyString() );
300            }
301    
302            IDGenerator idg = IDGenerator.getInstance();
303            return GetFeature.create( String.valueOf( idg.generateUniqueID() ), doc.getDocumentElement() );
304        }
305    
306    }