001    //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_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: 21877 $
082     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
083     * @author last edited by: $Author: aschmitz $
084     * 
085     * @version 1.0. $Revision: 21877 $, $Date: 2010-01-12 09:03:37 +0100 (Di, 12 Jan 2010) $
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            if ( qn.getNamespace() != null ) {
232                sb.append( "&NAMESPACE=xmlns(" ).append( qn.getPrefix() ).append( '=' );
233                sb.append( qn.getNamespace().toASCIIString() ).append( ')' );
234            }
235            LOG.logDebug( "DescribeFeaturetType for UserLayer: ", sb );
236            GMLSchemaDocument doc = new GMLSchemaDocument();
237            doc.load( new URL( sb.toString() ) );
238            return doc;
239        }
240    
241        /**
242         * @param layer
243         * @return the service instance
244         * @throws OGCWebServiceException
245         *             if no service could be found
246         */
247        protected OGCWebService getResponsibleService( AbstractLayer layer )
248                                throws OGCWebServiceException {
249    
250            LayerFeatureConstraints lfc = layer.getLayerFeatureConstraints();
251            FeatureTypeConstraint[] ftc = lfc.getFeatureTypeConstraint();
252            Layer root = handler.getConfiguration().getLayer();
253            OGCWebService wfs = findService( root, ftc[0].getFeatureTypeName() );
254            if ( wfs == null ) {
255                throw new OGCWebServiceException( this.getClass().getName(), "feature type: " + ftc[0].getFeatureTypeName()
256                                                                             + " is not served by this WMS/WFS" );
257            }
258    
259            return wfs;
260        }
261    
262        /**
263         * searches/findes the WFService that is resposible for handling the feature types of the current request. If no
264         * WFService instance can be found <code>null</code> will be returned to indicated that the current feature type is
265         * not served by the internal WFS of a WMS
266         * 
267         * @param layer
268         * @param featureType
269         * @return the service instance or null
270         * @throws OGCWebServiceException
271         */
272        private OGCWebService findService( Layer layer, QualifiedName featureType )
273                                throws OGCWebServiceException {
274            Layer[] layers = layer.getLayer();
275            for ( int i = 0; i < layers.length; i++ ) {
276                AbstractDataSource[] ad = layers[i].getDataSource();
277                if ( ad != null ) {
278                    for ( int j = 0; j < ad.length; j++ ) {
279                        if ( ad[j].getName().equals( featureType ) ) {
280    
281                            return ad[j].getOGCWebService();
282                        }
283                    }
284                }
285                // recursion
286                OGCWebService wfs = findService( layers[i], featureType );
287                if ( wfs != null ) {
288                    return wfs;
289                }
290            }
291    
292            return null;
293        }
294    
295        /**
296         * extracts all used namespace definitions from a set of PropertyPath's
297         * 
298         * @param pp
299         * @return the used namespace definitions from a set of PropertyPath's
300         */
301        protected Map<String, URI> extractNameSpaceDef( List<PropertyPath> pp ) {
302            Map<String, URI> map = new HashMap<String, URI>();
303            for ( int i = 0; i < pp.size(); i++ ) {
304                NamespaceContext nsc = pp.get( i ).getNamespaceContext();
305                map.putAll( nsc.getNamespaceMap() );
306            }
307            return map;
308        }
309    
310    }