001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/ogcwebservices/wfs/operation/DescribeFeatureType.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.wfs.operation;
037    
038    import java.net.URI;
039    import java.util.HashMap;
040    import java.util.Map;
041    
042    import org.deegree.datatypes.QualifiedName;
043    import org.deegree.framework.log.ILogger;
044    import org.deegree.framework.log.LoggerFactory;
045    import org.deegree.framework.util.IDGenerator;
046    import org.deegree.framework.util.KVP2Map;
047    import org.deegree.ogcwebservices.InconsistentRequestException;
048    import org.deegree.ogcwebservices.InvalidParameterValueException;
049    import org.deegree.ogcwebservices.MissingParameterValueException;
050    import org.deegree.ogcwebservices.OGCWebServiceException;
051    import org.deegree.ogcwebservices.wfs.WFService;
052    import org.w3c.dom.Element;
053    
054    /**
055     * Represents a <code>DescribeFeatureType</code> request to a web feature service.
056     * <p>
057     * The function of the DescribeFeatureType interface is to provide a client the means to request a
058     * schema definition of any feature type that a particular WFS can service. The description that is
059     * generated will define how a WFS expects a client application to express the state of a feature to
060     * be created or the new state of a feature to be updated. The result of a DescribeFeatureType
061     * request is an XML document, describing one or more feature types serviced by the WFS.
062     *
063     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
064     * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider</a>
065     * @author last edited by: $Author: mschneider $
066     *
067     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
068     */
069    public class DescribeFeatureType extends AbstractWFSRequest {
070    
071        private static final long serialVersionUID = 4403179045869238426L;
072    
073        private static ILogger LOG = LoggerFactory.getLogger( DescribeFeatureType.class );
074    
075        private String outputFormat;
076    
077        private QualifiedName[] typeNames;
078    
079        /**
080         * Creates a new <code>DescribeFeatureType</code> instance.
081         *
082         * @param version
083         * @param id
084         * @param handle
085         * @param outputFormat
086         * @param typeNames
087         * @param vendorspecificParameter
088         */
089        DescribeFeatureType( String version, String id, String handle, String outputFormat, QualifiedName[] typeNames,
090                             Map<String, String> vendorspecificParameter ) {
091            super( version, id, handle, vendorspecificParameter );
092            this.outputFormat = outputFormat;
093            this.typeNames = typeNames;
094        }
095    
096        /**
097         * Creates a <code>DescribeFeatureType</code> instance from a document that contains the DOM
098         * representation of the request.
099         *
100         * @param id
101         * @param root
102         *            element that contains the DOM representation of the request
103         * @return DescribeFeatureType instance
104         * @throws OGCWebServiceException
105         */
106        public static DescribeFeatureType create( String id, Element root )
107                                throws OGCWebServiceException {
108            DescribeFeatureTypeDocument doc = new DescribeFeatureTypeDocument();
109            doc.setRootElement( root );
110            DescribeFeatureType request;
111            try {
112                request = doc.parse( id );
113            } catch ( Exception e ) {
114                throw new OGCWebServiceException( "DescribeFeatureType", e.getMessage() );
115            }
116            return request;
117        }
118    
119        /**
120         * Creates a new <code>DescribeFeatureType</code> instance from the given key-value pair
121         * encoded request.
122         *
123         * @param id
124         *            request identifier
125         * @param request
126         * @return new <code>DescribeFeatureType</code> request
127         * @throws InvalidParameterValueException
128         * @throws InconsistentRequestException
129         * @throws MissingParameterValueException
130         */
131        public static DescribeFeatureType create( String id, String request )
132                                throws InconsistentRequestException, InvalidParameterValueException,
133                                MissingParameterValueException {
134            Map<String, String> map = KVP2Map.toMap( request );
135            map.put( "ID", id );
136            return create( map );
137        }
138    
139        /**
140         * Creates a new <code>DescribeFeatureType</code> request from the given map.
141         *
142         * @param request
143         * @return new <code>DescribeFeatureType</code> request
144         * @throws InconsistentRequestException
145         * @throws InvalidParameterValueException
146         * @throws MissingParameterValueException
147         */
148        public static DescribeFeatureType create( Map<String, String> request )
149                                throws InconsistentRequestException, InvalidParameterValueException,
150                                MissingParameterValueException {
151            checkServiceParameter( request );
152            String version = checkVersionParameter( request );
153            boolean is100 = version.equals( "1.0.0" );
154            // I guess XMLSCHEMA should be used here for 1.0.0, but what the heck, it's also kind of
155            // GML2...
156            // the problem is probably inheritance, since the AbstractWFSRequest defines the Strings
157            String outputFormat = getParam( "OUTPUTFORMAT", request, is100 ? FORMAT_GML2_WFS100 : FORMAT_GML3 );
158            if ( outputFormat.equalsIgnoreCase( "xmlschema" ) ) {
159                outputFormat = FORMAT_GML2_WFS100;
160            }
161            QualifiedName[] typeNames = extractTypeNames( request );
162    
163            long l = IDGenerator.getInstance().generateUniqueID();
164            String id = Long.toString( l );
165            return new DescribeFeatureType( version, id, null, outputFormat, typeNames, request );
166        }
167    
168        /**
169         * Returns the value of the outputFormat attribute.
170         * <p>
171         * The outputFormat attribute, is used to indicate the schema description language that should
172         * be used to describe a feature schema. The only mandated format is XML-Schema denoted by the
173         * XMLSCHEMA element; other vendor specific formats specified in the capabilities document are
174         * also possible.
175         *
176         * @return the value of the outputFormat attribute.
177         */
178        public String getOutputFormat() {
179            return this.outputFormat;
180        }
181    
182        /**
183         * Returns the names of the feature types for which the schema is requested.
184         * <p>
185         *
186         * @return the names of the feature types for which the schema is requested.
187         */
188        public QualifiedName[] getTypeNames() {
189            return typeNames;
190        }
191    
192        /**
193         * Adds missing namespaces in the names of requested feature types.
194         * <p>
195         * If the {@link QualifiedName} of a requested type has a null namespace, the first qualified
196         * feature type name of the given {@link WFService} with the same local name is used instead.
197         * <p>
198         * Note: The method changes this request (the feature type names) and should only be called by
199         * the <code>WFSHandler</code> class.
200         *
201         * @param wfs
202         *            {@link WFService} instance that is used for the lookup of proper (qualified)
203         *            feature type names
204         */
205        public void guessMissingNamespaces( WFService wfs ) {
206            for ( int i = 0; i < typeNames.length; i++ ) {
207                QualifiedName typeName = typeNames[i];
208                if ( typeName.getNamespace() == null ) {
209                    if ( typeName.getLocalName().equals( typeName.getLocalName() ) ) {
210                        LOG.logWarning( "Requested feature type name has no namespace information. Guessing namespace for feature type '"
211                                        + typeName.getLocalName() + "' (quirks lookup mode)." );
212                        for ( QualifiedName ftName : wfs.getMappedFeatureTypes().keySet() ) {
213                            if ( ftName.getLocalName().equals( typeName.getLocalName() ) ) {
214                                LOG.logWarning( "Using feature type '" + ftName + "'." );
215                                typeNames[i] = ftName;
216                                break;
217                            }
218                        }
219                    }
220                }
221            }
222        }
223    
224        /**
225         * Returns a string representation of the object.
226         *
227         * @return a string representation of the object.
228         */
229        @Override
230        public String toString() {
231            String ret = this.getClass().getName() + ":\n";
232            ret += ( outputFormat + "\n" );
233            if ( typeNames != null ) {
234                for ( int i = 0; i < typeNames.length; i++ ) {
235                    ret += ( typeNames[i] + "\n" );
236                }
237            }
238            return ret;
239        }
240    
241        @Override
242        public String getRequestParameter()
243                                throws OGCWebServiceException {
244            Map<URI, String> namespaces = new HashMap<URI, String>();
245            String typename = "";
246            String namespace = "";
247            for ( QualifiedName type : typeNames ) {
248                if ( typename.length() != 0 ) {
249                    typename += ',';
250                }
251                typename += type.getPrefixedName();
252    
253                if ( type.getNamespace() != null ) {
254                    if ( namespaces.get( type.getNamespace() ) != null ) {
255                        namespaces.put( type.getNamespace(), type.getPrefix() );
256                        if ( namespace.length() != 0 ) {
257                            namespace += ',';
258                        }
259                        namespace += type.getPrefix() + '=' + type.getNamespace();
260                    }
261                }
262            }
263    
264            String request = "request=DescribeFeatureType&version=" + this.getVersion() + "&typename=" + typename;
265            if ( namespace.length() != 0 ) {
266                request += "&namespace=xmlns(" + namespace + ')';
267            }
268            return request;
269        }
270    
271    }