001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/ogcwebservices/wms/GetMapServiceInvoker.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     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: 9345 $
088     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
089     * @author last edited by: $Author: apoth $
090     * 
091     * @version 1.0. $Revision: 9345 $, $Date: 2007-12-27 17:22:25 +0100 (Do, 27 Dez 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 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
123         * FeatureTypeConstraints and extracts the geometry property definition. The names of the
124         * geometry properties will be added as PropertyPath's 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                    GeometryPropertyType[] gpt = ft.getGeometryProperties();
153    
154                    List<PropertyPath> tmp = new ArrayList<PropertyPath>( gpt.length );
155                    for ( int j = 0; j < gpt.length; j++ ) {
156                        try {
157                            String pre = ftc[i].getFeatureTypeName().getPrefix();
158                            QualifiedName qn = new QualifiedName( pre, gpt[j].getName().getLocalName(),
159                                                                  gpt[j].getName().getNamespace() );
160                            PropertyPathStep step = new ElementStep( qn );
161                            List<PropertyPathStep> steps = new ArrayList<PropertyPathStep>();
162                            steps.add( step );
163                            PropertyPath prop = new PropertyPath( steps );
164                            pp.add( prop );
165                            tmp.add( prop );
166                        } catch ( Exception e ) {
167                            e.printStackTrace();
168                        }
169                    }
170                    geoProps.put( ftc[i].getFeatureTypeName(), tmp );
171                } else {
172                    List<PropertyPath> tmp = geoProps.get( ftc[i].getFeatureTypeName() );
173                    pp.addAll( tmp );
174                }
175    
176            }
177    
178            return pp;
179        }
180    
181        /**
182         * accesses the GML schema assigned to the feature type contained within the passed
183         * FeatureTypeConstraint from a remote WFS by performing a DescribeFeatureType request
184         * 
185         * @param layer
186         * @param ftc
187         * @return the schema document
188         * @throws InconsistentRequestException
189         * @throws InvalidParameterValueException
190         * @throws OGCWebServiceException
191         */
192        private GMLSchemaDocument getSchemaFromLocalWFS( AbstractLayer layer, FeatureTypeConstraint ftc )
193                                throws InconsistentRequestException, InvalidParameterValueException, OGCWebServiceException {
194            StringBuffer sb = new StringBuffer( 300 );
195            sb.append( "SERVICE=WFS&VERSION=1.1.0&REQUEST=DescribeFeatureType&TYPENAME=" );
196            QualifiedName qn = ftc.getFeatureTypeName();
197            sb.append( qn.getPrefixedName() );
198            sb.append( "&NAMESPACE=xmlns(" ).append( qn.getPrefix() ).append( '=' );
199            sb.append( qn.getNamespace().toASCIIString() ).append( ')' );
200            LOG.logDebug( "DescribeFeaturetType for UserLayer: ", sb );
201            DescribeFeatureType dft = DescribeFeatureType.create( "rt", sb.toString() );
202            WFService wfs = getResponsibleService( layer );
203            FeatureTypeDescription ftd = (FeatureTypeDescription) wfs.doService( dft );
204            GMLSchemaDocument doc = new GMLSchemaDocument();
205            doc.setRootElement( ftd.getFeatureTypeSchema().getRootElement() );
206            return doc;
207        }
208    
209        /**
210         * accesses the GML schema assigned to the feature type contained within the passed
211         * FeatureTypeConstraint from a local WFS by performing a DescribeFeatureType request
212         * 
213         * @param ftc
214         * @return the schema document
215         * @throws IOException
216         * @throws SAXException
217         * @throws MalformedURLException
218         */
219        private GMLSchemaDocument getSchemaFromRemoteWFS( UserLayer layer, FeatureTypeConstraint ftc )
220                                throws IOException, SAXException, MalformedURLException {
221            URL url = layer.getRemoteOWS().getOnlineResource();
222            StringBuffer sb = new StringBuffer( 300 );
223            sb.append( OWSUtils.validateHTTPGetBaseURL( url.toExternalForm() ) );
224            sb.append( "SERVICE=WFS&VERSION=1.1.0&REQUEST=DescribeFeatureType&TYPENAME=" );
225            QualifiedName qn = ftc.getFeatureTypeName();
226            sb.append( qn.getPrefixedName() );
227            sb.append( "&NAMESPACE=xmlns(" ).append( qn.getPrefix() ).append( '=' );
228            sb.append( qn.getNamespace().toASCIIString() ).append( ')' );
229            LOG.logDebug( "DescribeFeaturetType for UserLayer: ", sb );
230            GMLSchemaDocument doc = new GMLSchemaDocument();
231            doc.load( new URL( sb.toString() ) );
232            return doc;
233        }
234    
235        /**
236         * @return the service instance
237         * @throws OGCWebServiceException
238         *             if no service could be found
239         */
240        protected WFService getResponsibleService( AbstractLayer layer )
241                                throws OGCWebServiceException {
242    
243            LayerFeatureConstraints lfc = layer.getLayerFeatureConstraints();
244            FeatureTypeConstraint[] ftc = lfc.getFeatureTypeConstraint();
245            Layer root = handler.getConfiguration().getLayer();
246            WFService wfs = findService( root, ftc[0].getFeatureTypeName() );
247            if ( wfs == null ) {
248                throw new OGCWebServiceException( this.getClass().getName(), "feature type: " + ftc[0].getFeatureTypeName()
249                                                                             + " is not served by this WMS/WFS" );
250            }
251    
252            return wfs;
253        }
254    
255        /**
256         * searches/findes the WFService that is resposible for handling the feature types of the
257         * current request. If no WFService instance can be found <code>null</code> will be returned
258         * to indicated that the current feature type is not served by the internal WFS of a WMS
259         * 
260         * @param layer
261         * @param featureType
262         * @return the service instance or null
263         * @throws OGCWebServiceException
264         */
265        private WFService findService( Layer layer, QualifiedName featureType )
266                                throws OGCWebServiceException {
267            Layer[] layers = layer.getLayer();
268            for ( int i = 0; i < layers.length; i++ ) {
269                AbstractDataSource[] ad = layers[i].getDataSource();
270                if ( ad != null ) {
271                    for ( int j = 0; j < ad.length; j++ ) {
272                        if ( ad[j].getName().equals( featureType ) ) {
273                            return (WFService) ad[j].getOGCWebService();
274                        }
275                    }
276                }
277                // recursion
278                WFService wfs = findService( layers[i], featureType );
279                if ( wfs != null ) {
280                    return wfs;
281                }
282            }
283    
284            return null;
285        }
286    
287        /**
288         * extracts all used namespace definitions from a set of PropertyPath's
289         * 
290         * @param pp
291         * @return the used namespace definitions from a set of PropertyPath's
292         */
293        protected Map<String, URI> extractNameSpaceDef( List<PropertyPath> pp ) {
294            Map<String, URI> map = new HashMap<String, URI>();
295            for ( int i = 0; i < pp.size(); i++ ) {
296                NamespaceContext nsc = pp.get( i ).getNamespaceContext();
297                map.putAll( nsc.getNamespaceMap() );
298            }
299            return map;
300        }
301    
302    }