001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/ogcwebservices/wms/GetMapServiceInvoker.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2007 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     Aennchenstr. 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    package org.deegree.ogcwebservices.wms;
044    
045    import java.io.IOException;
046    import java.net.MalformedURLException;
047    import java.net.URI;
048    import java.net.URL;
049    import java.util.ArrayList;
050    import java.util.HashMap;
051    import java.util.List;
052    import java.util.Map;
053    
054    import org.deegree.datatypes.QualifiedName;
055    import org.deegree.framework.log.ILogger;
056    import org.deegree.framework.log.LoggerFactory;
057    import org.deegree.framework.xml.NamespaceContext;
058    import org.deegree.framework.xml.XMLParsingException;
059    import org.deegree.framework.xml.schema.XMLSchemaException;
060    import org.deegree.graphics.sld.AbstractLayer;
061    import org.deegree.graphics.sld.FeatureTypeConstraint;
062    import org.deegree.graphics.sld.LayerFeatureConstraints;
063    import org.deegree.graphics.sld.UserLayer;
064    import org.deegree.model.crs.UnknownCRSException;
065    import org.deegree.model.feature.schema.FeatureType;
066    import org.deegree.model.feature.schema.GMLSchema;
067    import org.deegree.model.feature.schema.GMLSchemaDocument;
068    import org.deegree.model.feature.schema.GeometryPropertyType;
069    import org.deegree.ogcbase.ElementStep;
070    import org.deegree.ogcbase.PropertyPath;
071    import org.deegree.ogcbase.PropertyPathStep;
072    import org.deegree.ogcwebservices.InconsistentRequestException;
073    import org.deegree.ogcwebservices.InvalidParameterValueException;
074    import org.deegree.ogcwebservices.OGCWebServiceException;
075    import org.deegree.ogcwebservices.OWSUtils;
076    import org.deegree.ogcwebservices.wfs.WFService;
077    import org.deegree.ogcwebservices.wfs.operation.DescribeFeatureType;
078    import org.deegree.ogcwebservices.wfs.operation.FeatureTypeDescription;
079    import org.deegree.ogcwebservices.wms.capabilities.Layer;
080    import org.deegree.ogcwebservices.wms.configuration.AbstractDataSource;
081    import org.xml.sax.SAXException;
082    
083    /**
084     * 
085     * 
086     * 
087     * @version $Revision: 6891 $
088     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
089     * @author last edited by: $Author: aschmitz $
090     * 
091     * @version 1.0. $Revision: 6891 $, $Date: 2007-05-08 14:02:55 +0200 (Di, 08 Mai 2007) $
092     * 
093     * @since 2.0
094     */
095    public abstract class GetMapServiceInvoker {
096    
097        private static final ILogger LOG = LoggerFactory.getLogger( GetMapServiceInvoker.class );
098    
099        private static Map<QualifiedName, List<PropertyPath>> geoProps;
100    
101        static {
102            if ( geoProps == null ) {
103                geoProps = new HashMap<QualifiedName, List<PropertyPath>>();
104            }
105        }
106    
107        protected final DefaultGetMapHandler handler;
108    
109        protected int index = 0;
110    
111        protected double scaleDen = 0;
112    
113        /**
114         * 
115         * @param handler
116         * @param index
117         * @param scaleDen
118         */
119        public GetMapServiceInvoker( DefaultGetMapHandler handler, int index, double scaleDen ) {
120            this.handler = handler;
121            this.index = index;
122            this.scaleDen = scaleDen;
123        }
124    
125        /**
126         * the method accesses the GML schema of the feature types being part of the passed
127         * FeatureTypeConstraints and extracts the geometry property definition. The names of the
128         * geometry properties will be added as PropertyPath's to passed list
129         * 
130         * @param layer
131         * @param ftc
132         * @param pp
133         * @return the list of property paths
134         * @throws OGCWebServiceException
135         * @throws SAXException
136         * @throws IOException
137         * @throws XMLParsingException
138         * @throws XMLSchemaException
139         * @throws UnknownCRSException
140         */
141        protected List<PropertyPath> findGeoProperties( AbstractLayer layer, FeatureTypeConstraint[] ftc,
142                                                        List<PropertyPath> pp )
143                                throws OGCWebServiceException, IOException, SAXException, XMLSchemaException,
144                                XMLParsingException, UnknownCRSException {
145    
146            GMLSchemaDocument doc = null;
147            for ( int i = 0; i < ftc.length; i++ ) {
148                if ( geoProps.get( ftc[i].getFeatureTypeName() ) == null ) {
149                    if ( layer instanceof UserLayer && ( (UserLayer) layer ).getRemoteOWS() != null ) {
150                        doc = getSchemaFromRemoteWFS( (UserLayer) layer, ftc[i] );
151                    } else {
152                        doc = getSchemaFromLocalWFS( layer, ftc[i] );
153                    }
154                    GMLSchema schema = doc.parseGMLSchema();
155                    FeatureType ft = schema.getFeatureType( ftc[i].getFeatureTypeName() );
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
187         * FeatureTypeConstraint from a 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            WFService 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
215         * FeatureTypeConstraint from a 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         * @return the service instance
241         * @throws OGCWebServiceException
242         *             if no service could be found
243         */
244        protected WFService getResponsibleService( AbstractLayer layer )
245                                throws OGCWebServiceException {
246    
247            LayerFeatureConstraints lfc = layer.getLayerFeatureConstraints();
248            FeatureTypeConstraint[] ftc = lfc.getFeatureTypeConstraint();
249            Layer root = handler.getConfiguration().getLayer();
250            WFService wfs = findService( root, ftc[0].getFeatureTypeName() );
251            if ( wfs == null ) {
252                throw new OGCWebServiceException( this.getClass().getName(), "feature type: " + ftc[0].getFeatureTypeName()
253                                                                             + " is not served by this WMS/WFS" );
254            }
255    
256            return wfs;
257        }
258    
259        /**
260         * searches/findes the WFService that is resposible for handling the feature types of the
261         * current request. If no WFService instance can be found <code>null</code> will be returned
262         * to indicated that the current feature type is not served by the internal WFS of a WMS
263         * 
264         * @param layer
265         * @param featureType
266         * @return the service instance or null
267         * @throws OGCWebServiceException
268         */
269        private WFService findService( Layer layer, QualifiedName featureType )
270                                throws OGCWebServiceException {
271            Layer[] layers = layer.getLayer();
272            for ( int i = 0; i < layers.length; i++ ) {
273                AbstractDataSource[] ad = layers[i].getDataSource();
274                if ( ad != null ) {
275                    for ( int j = 0; j < ad.length; j++ ) {
276                        if ( ad[j].getName().equals( featureType ) ) {
277                            return (WFService) ad[j].getOGCWebService();
278                        }
279                    }
280                }
281                // recursion
282                WFService wfs = findService( layers[i], featureType );
283                if ( wfs != null ) {
284                    return wfs;
285                }
286            }
287    
288            return null;
289        }
290    
291        /**
292         * extracts all used namespace definitions from a set of PropertyPath's
293         * 
294         * @param pp
295         * @return the used namespace definitions from a set of PropertyPath's
296         */
297        protected Map<String, URI> extractNameSpaceDef( List<PropertyPath> pp ) {
298            Map<String, URI> map = new HashMap<String, URI>();
299            for ( int i = 0; i < pp.size(); i++ ) {
300                NamespaceContext nsc = pp.get( i ).getNamespaceContext();
301                map.putAll( nsc.getNamespaceMap() );
302            }
303            return map;
304        }
305    
306    }