001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/ogcwebservices/wms/GetMapServiceInvoker.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    package org.deegree.ogcwebservices.wms;
037    
038    import java.io.IOException;
039    import java.net.MalformedURLException;
040    import java.net.URI;
041    import java.net.URL;
042    import java.util.ArrayList;
043    import java.util.HashMap;
044    import java.util.List;
045    import java.util.Map;
046    
047    import org.deegree.datatypes.QualifiedName;
048    import org.deegree.framework.log.ILogger;
049    import org.deegree.framework.log.LoggerFactory;
050    import org.deegree.framework.xml.NamespaceContext;
051    import org.deegree.framework.xml.XMLParsingException;
052    import org.deegree.framework.xml.schema.XMLSchemaException;
053    import org.deegree.graphics.sld.AbstractLayer;
054    import org.deegree.graphics.sld.FeatureTypeConstraint;
055    import org.deegree.graphics.sld.LayerFeatureConstraints;
056    import org.deegree.graphics.sld.UserLayer;
057    import org.deegree.i18n.Messages;
058    import org.deegree.model.crs.UnknownCRSException;
059    import org.deegree.model.feature.schema.FeatureType;
060    import org.deegree.model.feature.schema.GMLSchema;
061    import org.deegree.model.feature.schema.GMLSchemaDocument;
062    import org.deegree.model.feature.schema.GeometryPropertyType;
063    import org.deegree.ogcbase.ElementStep;
064    import org.deegree.ogcbase.PropertyPath;
065    import org.deegree.ogcbase.PropertyPathStep;
066    import org.deegree.ogcwebservices.InconsistentRequestException;
067    import org.deegree.ogcwebservices.InvalidParameterValueException;
068    import org.deegree.ogcwebservices.OGCWebService;
069    import org.deegree.ogcwebservices.OGCWebServiceException;
070    import org.deegree.ogcwebservices.OWSUtils;
071    import org.deegree.ogcwebservices.wfs.operation.DescribeFeatureType;
072    import org.deegree.ogcwebservices.wfs.operation.FeatureTypeDescription;
073    import org.deegree.ogcwebservices.wms.capabilities.Layer;
074    import org.deegree.ogcwebservices.wms.configuration.AbstractDataSource;
075    import org.xml.sax.SAXException;
076    
077    /**
078     *
079     *
080     *
081     * @version $Revision: 18195 $
082     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
083     * @author last edited by: $Author: mschneider $
084     *
085     * @version 1.0. $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
086     *
087     * @since 2.0
088     */
089    public abstract class GetMapServiceInvoker {
090    
091        private static final ILogger LOG = LoggerFactory.getLogger( GetMapServiceInvoker.class );
092    
093        private static Map<QualifiedName, List<PropertyPath>> geoProps;
094    
095        static {
096            if ( geoProps == null ) {
097                geoProps = new HashMap<QualifiedName, List<PropertyPath>>();
098            }
099        }
100    
101        /**
102         * default get map handler
103         */
104        protected final DefaultGetMapHandler handler;
105    
106        /**
107         * scale denominator
108         */
109        protected double scaleDen = 0;
110    
111        /**
112         *
113         * @param handler
114         * @param scaleDen
115         */
116        public GetMapServiceInvoker( DefaultGetMapHandler handler, double scaleDen ) {
117            this.handler = handler;
118            this.scaleDen = scaleDen;
119        }
120    
121        /**
122         * the method accesses the GML schema of the feature types being part of the passed FeatureTypeConstraints and
123         * extracts the geometry property definition. The names of the geometry properties will be added as PropertyPath's
124         * to passed list
125         *
126         * @param layer
127         * @param ftc
128         * @param pp
129         * @return the list of property paths
130         * @throws OGCWebServiceException
131         * @throws SAXException
132         * @throws IOException
133         * @throws XMLParsingException
134         * @throws XMLSchemaException
135         * @throws UnknownCRSException
136         */
137        protected List<PropertyPath> findGeoProperties( AbstractLayer layer, FeatureTypeConstraint[] ftc,
138                                                        List<PropertyPath> pp )
139                                throws OGCWebServiceException, IOException, SAXException, XMLSchemaException,
140                                XMLParsingException, UnknownCRSException {
141    
142            GMLSchemaDocument doc = null;
143            for ( int i = 0; i < ftc.length; i++ ) {
144                if ( geoProps.get( ftc[i].getFeatureTypeName() ) == null ) {
145                    if ( layer instanceof UserLayer && ( (UserLayer) layer ).getRemoteOWS() != null ) {
146                        doc = getSchemaFromRemoteWFS( (UserLayer) layer, ftc[i] );
147                    } else {
148                        doc = getSchemaFromLocalWFS( layer, ftc[i] );
149                    }
150                    GMLSchema schema = doc.parseGMLSchema();
151                    FeatureType ft = schema.getFeatureType( ftc[i].getFeatureTypeName() );
152                    if ( ft == null ) {
153                        throw new OGCWebServiceException( Messages.get( "WFS_FEATURE_TYPE_UNKNOWN",
154                                                                        ftc[i].getFeatureTypeName() ) );
155                    }
156                    GeometryPropertyType[] gpt = ft.getGeometryProperties();
157    
158                    List<PropertyPath> tmp = new ArrayList<PropertyPath>( gpt.length );
159                    for ( int j = 0; j < gpt.length; j++ ) {
160                        try {
161                            String pre = ftc[i].getFeatureTypeName().getPrefix();
162                            QualifiedName qn = new QualifiedName( pre, gpt[j].getName().getLocalName(),
163                                                                  gpt[j].getName().getNamespace() );
164                            PropertyPathStep step = new ElementStep( qn );
165                            List<PropertyPathStep> steps = new ArrayList<PropertyPathStep>();
166                            steps.add( step );
167                            PropertyPath prop = new PropertyPath( steps );
168                            pp.add( prop );
169                            tmp.add( prop );
170                        } catch ( Exception e ) {
171                            e.printStackTrace();
172                        }
173                    }
174                    geoProps.put( ftc[i].getFeatureTypeName(), tmp );
175                } else {
176                    List<PropertyPath> tmp = geoProps.get( ftc[i].getFeatureTypeName() );
177                    pp.addAll( tmp );
178                }
179    
180            }
181    
182            return pp;
183        }
184    
185        /**
186         * accesses the GML schema assigned to the feature type contained within the passed FeatureTypeConstraint from a
187         * remote WFS by performing a DescribeFeatureType request
188         *
189         * @param layer
190         * @param ftc
191         * @return the schema document
192         * @throws InconsistentRequestException
193         * @throws InvalidParameterValueException
194         * @throws OGCWebServiceException
195         */
196        private GMLSchemaDocument getSchemaFromLocalWFS( AbstractLayer layer, FeatureTypeConstraint ftc )
197                                throws InconsistentRequestException, InvalidParameterValueException, OGCWebServiceException {
198            StringBuffer sb = new StringBuffer( 300 );
199            sb.append( "SERVICE=WFS&VERSION=1.1.0&REQUEST=DescribeFeatureType&TYPENAME=" );
200            QualifiedName qn = ftc.getFeatureTypeName();
201            sb.append( qn.getPrefixedName() );
202            sb.append( "&NAMESPACE=xmlns(" ).append( qn.getPrefix() ).append( '=' );
203            sb.append( qn.getNamespace().toASCIIString() ).append( ')' );
204            LOG.logDebug( "DescribeFeaturetType for UserLayer: ", sb );
205            DescribeFeatureType dft = DescribeFeatureType.create( "rt", sb.toString() );
206            OGCWebService wfs = getResponsibleService( layer );
207            FeatureTypeDescription ftd = (FeatureTypeDescription) wfs.doService( dft );
208            GMLSchemaDocument doc = new GMLSchemaDocument();
209            doc.setRootElement( ftd.getFeatureTypeSchema().getRootElement() );
210            return doc;
211        }
212    
213        /**
214         * accesses the GML schema assigned to the feature type contained within the passed FeatureTypeConstraint from a
215         * local WFS by performing a DescribeFeatureType request
216         *
217         * @param ftc
218         * @return the schema document
219         * @throws IOException
220         * @throws SAXException
221         * @throws MalformedURLException
222         */
223        private GMLSchemaDocument getSchemaFromRemoteWFS( UserLayer layer, FeatureTypeConstraint ftc )
224                                throws IOException, SAXException, MalformedURLException {
225            URL url = layer.getRemoteOWS().getOnlineResource();
226            StringBuffer sb = new StringBuffer( 300 );
227            sb.append( OWSUtils.validateHTTPGetBaseURL( url.toExternalForm() ) );
228            sb.append( "SERVICE=WFS&VERSION=1.1.0&REQUEST=DescribeFeatureType&TYPENAME=" );
229            QualifiedName qn = ftc.getFeatureTypeName();
230            sb.append( qn.getPrefixedName() );
231            sb.append( "&NAMESPACE=xmlns(" ).append( qn.getPrefix() ).append( '=' );
232            sb.append( qn.getNamespace().toASCIIString() ).append( ')' );
233            LOG.logDebug( "DescribeFeaturetType for UserLayer: ", sb );
234            GMLSchemaDocument doc = new GMLSchemaDocument();
235            doc.load( new URL( sb.toString() ) );
236            return doc;
237        }
238    
239        /**
240         * @param layer
241         * @return the service instance
242         * @throws OGCWebServiceException
243         *             if no service could be found
244         */
245        protected OGCWebService getResponsibleService( AbstractLayer layer )
246                                throws OGCWebServiceException {
247    
248            LayerFeatureConstraints lfc = layer.getLayerFeatureConstraints();
249            FeatureTypeConstraint[] ftc = lfc.getFeatureTypeConstraint();
250            Layer root = handler.getConfiguration().getLayer();
251            OGCWebService wfs = findService( root, ftc[0].getFeatureTypeName() );
252            if ( wfs == null ) {
253                throw new OGCWebServiceException( this.getClass().getName(), "feature type: " + ftc[0].getFeatureTypeName()
254                                                                             + " is not served by this WMS/WFS" );
255            }
256    
257            return wfs;
258        }
259    
260        /**
261         * searches/findes the WFService that is resposible for handling the feature types of the current request. If no
262         * WFService instance can be found <code>null</code> will be returned to indicated that the current feature type is
263         * not served by the internal WFS of a WMS
264         *
265         * @param layer
266         * @param featureType
267         * @return the service instance or null
268         * @throws OGCWebServiceException
269         */
270        private OGCWebService findService( Layer layer, QualifiedName featureType )
271                                throws OGCWebServiceException {
272            Layer[] layers = layer.getLayer();
273            for ( int i = 0; i < layers.length; i++ ) {
274                AbstractDataSource[] ad = layers[i].getDataSource();
275                if ( ad != null ) {
276                    for ( int j = 0; j < ad.length; j++ ) {
277                        if ( ad[j].getName().equals( featureType ) ) {
278    
279                            return ad[j].getOGCWebService();
280                        }
281                    }
282                }
283                // recursion
284                OGCWebService wfs = findService( layers[i], featureType );
285                if ( wfs != null ) {
286                    return wfs;
287                }
288            }
289    
290            return null;
291        }
292    
293        /**
294         * extracts all used namespace definitions from a set of PropertyPath's
295         *
296         * @param pp
297         * @return the used namespace definitions from a set of PropertyPath's
298         */
299        protected Map<String, URI> extractNameSpaceDef( List<PropertyPath> pp ) {
300            Map<String, URI> map = new HashMap<String, URI>();
301            for ( int i = 0; i < pp.size(); i++ ) {
302                NamespaceContext nsc = pp.get( i ).getNamespaceContext();
303                map.putAll( nsc.getNamespaceMap() );
304            }
305            return map;
306        }
307    
308    }