001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/ogcwebservices/wfs/configuration/WFSConfigurationDocument.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.configuration;
037    
038    import static org.deegree.framework.xml.XMLTools.getNodeAsBoolean;
039    import static org.deegree.framework.xml.XMLTools.getRequiredElement;
040    
041    import java.io.File;
042    import java.net.URI;
043    import java.net.URL;
044    import java.util.HashMap;
045    import java.util.List;
046    import java.util.Map;
047    
048    import org.deegree.datatypes.QualifiedName;
049    import org.deegree.framework.log.ILogger;
050    import org.deegree.framework.log.LoggerFactory;
051    import org.deegree.framework.util.CharsetUtils;
052    import org.deegree.framework.util.StringTools;
053    import org.deegree.framework.xml.InvalidConfigurationException;
054    import org.deegree.framework.xml.XMLParsingException;
055    import org.deegree.framework.xml.XMLTools;
056    import org.deegree.model.metadata.iso19115.Keywords;
057    import org.deegree.model.metadata.iso19115.OnlineResource;
058    import org.deegree.model.spatialschema.Envelope;
059    import org.deegree.ogcwebservices.getcapabilities.DCPType;
060    import org.deegree.ogcwebservices.getcapabilities.HTTP;
061    import org.deegree.ogcwebservices.getcapabilities.MetadataURL;
062    import org.deegree.ogcwebservices.getcapabilities.Operation;
063    import org.deegree.ogcwebservices.getcapabilities.OperationsMetadata;
064    import org.deegree.ogcwebservices.getcapabilities.Protocol;
065    import org.deegree.ogcwebservices.wfs.capabilities.FormatType;
066    import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilitiesDocument;
067    import org.deegree.ogcwebservices.wfs.capabilities.WFSFeatureType;
068    import org.deegree.ogcwebservices.wfs.capabilities.WFSOperationsMetadata;
069    import org.deegree.owscommon.OWSDomainType;
070    import org.w3c.dom.Element;
071    import org.w3c.dom.Node;
072    
073    /**
074     * Represents an XML configuration document for a deegree WFS instance, i.e. it consists of all sections common to an
075     * OGC WFS 1.1 capabilities document plus some deegree specific elements.
076     *
077     * @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider </a>
078     * @author last edited by: $Author: mschneider $
079     *
080     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
081     */
082    public class WFSConfigurationDocument extends WFSCapabilitiesDocument {
083    
084        private static final long serialVersionUID = -6415476866015999971L;
085    
086        protected static final ILogger LOG = LoggerFactory.getLogger( WFSConfigurationDocument.class );
087    
088        /**
089         * Creates an object representation of the document.
090         *
091         * @return class representation of the configuration document
092         * @throws InvalidConfigurationException
093         */
094        public WFSConfiguration getConfiguration()
095                                throws InvalidConfigurationException {
096    
097            WFSConfiguration config = null;
098    
099            try {
100                WFSDeegreeParams deegreeParams = getDeegreeParams();
101    
102                // get default Urls (used when DCP element is ommitted in Operation-elements)
103                OnlineResource defaultOnlineResource = deegreeParams.getDefaultOnlineResource();
104                String defaultUrl = defaultOnlineResource.getLinkage().getHref().toString();
105                if ( defaultUrl.endsWith( "?" ) ) {
106                    defaultUrl = defaultUrl.substring( 0, defaultUrl.length() - 1 );
107                }
108                URL defaultUrlGet = new URL( defaultUrl + '?' );
109                URL defaultUrlPost = new URL( defaultUrl );
110    
111                OperationsMetadata opMetadata = getOperationsMetadata( defaultUrlGet, defaultUrlPost );
112                config = new WFSConfiguration( parseVersion(), parseUpdateSequence(), getServiceIdentification(),
113                                               getServiceProvider(), opMetadata, getFeatureTypeList(),
114                                               getServesGMLObjectTypeList(), getSupportsGMLObjectTypeList(), null,
115                                               getFilterCapabilities(), deegreeParams );
116            } catch ( Exception e ) {
117                throw new InvalidConfigurationException( e.getMessage() + "\n" + StringTools.stackTraceToString( e ) );
118            }
119            return config;
120        }
121    
122        /**
123         * Creates an object representation of the <code>deegreeParams</code>- section.
124         *
125         * @return class representation of the <code>deegreeParams</code>- section
126         * @throws InvalidConfigurationException
127         */
128        public WFSDeegreeParams getDeegreeParams()
129                                throws InvalidConfigurationException {
130    
131            WFSDeegreeParams deegreeParams = null;
132    
133            try {
134                Element element = (Element) XMLTools.getRequiredNode( getRootElement(), "deegreewfs:deegreeParams",
135                                                                      nsContext );
136                OnlineResource defaultOnlineResource = parseOnLineResource( getRequiredElement(
137                                                                                                element,
138                                                                                                "deegreewfs:DefaultOnlineResource",
139                                                                                                nsContext ) );
140                int cacheSize = XMLTools.getNodeAsInt( element, "deegreewfs:CacheSize/text()", nsContext, 100 );
141                int requestTimeLimit = XMLTools.getNodeAsInt( element, "deegreewfs:RequestTimeLimit/text()", nsContext, 10 );
142    
143                boolean checkUTMZones = getNodeAsBoolean( element, "deegreewfs:CheckUTMZones", nsContext, false );
144                boolean switchAxes = getNodeAsBoolean( element, "deegreewfs:SwitchAxesForEPSG4326", nsContext, false );
145                boolean printGeomIds = getNodeAsBoolean( element, "deegreewfs:PrintGeometryGmlIds", nsContext, false );
146    
147                String characterSet = XMLTools.getNodeAsString( element, "deegreewfs:Encoding/text()", nsContext,
148                                                                CharsetUtils.getSystemCharset() );
149                String[] dataDirectories = XMLTools.getNodesAsStrings(
150                                                                       element,
151                                                                       "deegreewfs:DataDirectoryList/deegreewfs:DataDirectory/text()",
152                                                                       nsContext );
153                if ( dataDirectories.length == 0 ) {
154                    LOG.logInfo( "No data directory specified. Using configuration document directory." );
155                    dataDirectories = new String[] { "." };
156                }
157                for ( int i = 0; i < dataDirectories.length; i++ ) {
158                    try {
159                        dataDirectories[i] = resolve( dataDirectories[i] ).toURI().getPath();
160                    } catch ( Exception e ) {
161                        String msg = "DataDirectory '" + dataDirectories[i] + "' cannot be resolved as a directory: "
162                                     + e.getMessage();
163                        throw new InvalidConfigurationException( msg );
164                    }
165                }
166    
167                String lockManagerString = XMLTools.getNodeAsString( element, "deegreewfs:LockManagerDirectory/text()",
168                                                                     nsContext, null );
169                File lockManagerDir = null;
170                if ( lockManagerString != null ) {
171                    try {
172                        lockManagerDir = new File( this.resolve( lockManagerString ).toURI().toURL().getFile() );
173                    } catch ( Exception e ) {
174                        String msg = "Specified value (" + lockManagerDir
175                                     + ") for 'deegreewfs:LockManagerDirectory' is invalid.";
176                        throw new InvalidConfigurationException( msg, e );
177                    }
178                }
179                deegreeParams = new WFSDeegreeParams( defaultOnlineResource, cacheSize, requestTimeLimit, characterSet,
180                                                      dataDirectories, lockManagerDir, checkUTMZones, switchAxes,
181                                                      printGeomIds );
182            } catch ( XMLParsingException e ) {
183                throw new InvalidConfigurationException( "Error parsing the deegreeParams "
184                                                         + "section of the WFS configuration: \n" + e.getMessage()
185                                                         + StringTools.stackTraceToString( e ) );
186            }
187            return deegreeParams;
188        }
189    
190        /**
191         * Creates an object representation of the <code>ows:OperationsMetadata</code> section.
192         *
193         * @param defaultUrlGet
194         * @param defaultUrlPost
195         * @return object representation of the <code>ows:OperationsMetadata</code> section
196         * @throws XMLParsingException
197         */
198        public OperationsMetadata getOperationsMetadata( URL defaultUrlGet, URL defaultUrlPost )
199                                throws XMLParsingException {
200    
201            List<Node> operationElementList = XMLTools.getNodes( getRootElement(), "ows:OperationsMetadata/ows:Operation",
202                                                                 nsContext );
203    
204            // build HashMap of 'ows:Operation'-elements for easier access
205            Map<String, Element> operations = new HashMap<String, Element>();
206            for ( int i = 0; i < operationElementList.size(); i++ ) {
207                operations.put( XMLTools.getRequiredNodeAsString( operationElementList.get( i ), "@name", nsContext ),
208                                (Element) operationElementList.get( i ) );
209            }
210    
211            Operation getCapabilities = getOperation( OperationsMetadata.GET_CAPABILITIES_NAME, true, operations,
212                                                      defaultUrlGet, defaultUrlPost );
213            Operation describeFeatureType = getOperation( WFSOperationsMetadata.DESCRIBE_FEATURETYPE_NAME, true,
214                                                          operations, defaultUrlGet, defaultUrlPost );
215            Operation getFeature = getOperation( WFSOperationsMetadata.GET_FEATURE_NAME, false, operations, defaultUrlGet,
216                                                 defaultUrlPost );
217            Operation getFeatureWithLock = getOperation( WFSOperationsMetadata.GET_FEATURE_WITH_LOCK_NAME, false,
218                                                         operations, defaultUrlGet, defaultUrlPost );
219            Operation getGMLObject = getOperation( WFSOperationsMetadata.GET_GML_OBJECT_NAME, false, operations,
220                                                   defaultUrlGet, defaultUrlPost );
221            Operation lockFeature = getOperation( WFSOperationsMetadata.LOCK_FEATURE_NAME, false, operations,
222                                                  defaultUrlGet, defaultUrlPost );
223            Operation transaction = getOperation( WFSOperationsMetadata.TRANSACTION_NAME, false, operations, defaultUrlGet,
224                                                  defaultUrlPost );
225    
226            List<Element> parameterElementList = XMLTools.getElements( getRootElement(),
227                                                                       "ows:OperationsMetadata/ows:Parameter", nsContext );
228            OWSDomainType[] parameters = new OWSDomainType[parameterElementList.size()];
229            for ( int i = 0; i < parameters.length; i++ ) {
230                parameters[i] = getOWSDomainType( null, parameterElementList.get( i ) );
231            }
232    
233            List<Element> constraintElementList = XMLTools.getElements( getRootElement(),
234                                                                        "ows:OperationsMetadata/ows:Constraint", nsContext );
235            OWSDomainType[] constraints = new OWSDomainType[constraintElementList.size()];
236            for ( int i = 0; i < constraints.length; i++ ) {
237                constraints[i] = getOWSDomainType( null, constraintElementList.get( i ) );
238            }
239            WFSOperationsMetadata metadata = new WFSOperationsMetadata( getCapabilities, describeFeatureType, getFeature,
240                                                                        getFeatureWithLock, getGMLObject, lockFeature,
241                                                                        transaction, parameters, constraints );
242    
243            return metadata;
244        }
245    
246        /**
247         * Creates an object representation of an <code>ows:Operation</code>- element.
248         *
249         * @param name
250         * @param isMandatory
251         * @param operations
252         * @param defaultUrlGet
253         * @param defaultUrlPost
254         * @return object representation of <code>ows:Operation</code>- element
255         * @throws XMLParsingException
256         */
257        protected Operation getOperation( String name, boolean isMandatory, Map<String, Element> operations,
258                                          URL defaultUrlGet, URL defaultUrlPost )
259                                throws XMLParsingException {
260    
261            Operation operation = null;
262            Element operationElement = operations.get( name );
263            if ( operationElement == null ) {
264                if ( isMandatory ) {
265                    throw new XMLParsingException( "Mandatory operation '" + name + "' not defined in "
266                                                   + "'OperationsMetadata'-section." );
267                }
268            } else {
269                // "ows:Parameter"-elements
270                List<Element> parameterElements = XMLTools.getElements( operationElement, "ows:Parameter", nsContext );
271                OWSDomainType[] parameters = new OWSDomainType[parameterElements.size()];
272                for ( int i = 0; i < parameters.length; i++ ) {
273                    parameters[i] = getOWSDomainType( name, parameterElements.get( i ) );
274                }
275    
276                DCPType[] dcps = null;
277                List<Element> nl = XMLTools.getElements( operationElement, "ows:DCP", nsContext );
278                if ( nl.size() > 0 ) {
279                    dcps = getDCPs( nl );
280                } else {
281                    // add default URLs
282                    dcps = new DCPType[1];
283                    Protocol protocol = new HTTP( new URL[] { defaultUrlGet }, new URL[] { defaultUrlPost } );
284                    dcps[0] = new DCPType( protocol );
285                }
286                operation = new Operation( name, dcps, parameters );
287            }
288            return operation;
289        }
290    
291        /**
292         * Returns the object representation for an element of type <code>wfs:FeatureTypeType</code>.
293         *
294         * @param element
295         * @return object representation for the element of type <code>wfs:OperationsType</code>
296         * @throws XMLParsingException
297         */
298        @Override
299        public WFSFeatureType getFeatureTypeType( Element element )
300                                throws XMLParsingException {
301    
302            QualifiedName name = parseQualifiedName( XMLTools.getRequiredNode( element, "wfs:Name/text()", nsContext ) );
303            String title = XMLTools.getRequiredNodeAsString( element, "wfs:Title/text()", nsContext );
304            String abstract_ = XMLTools.getNodeAsString( element, "wfs:Abstract/text()", nsContext, null );
305            Keywords[] keywords = getKeywords( XMLTools.getNodes( element, "ows:Keywords", nsContext ) );
306    
307            URI defaultSrs = null;
308            URI[] otherSrs = null;
309            Node noSrsElement = XMLTools.getNode( element, "wfs:NoSRS", nsContext );
310            if ( noSrsElement == null ) {
311                defaultSrs = XMLTools.getNodeAsURI( element, "wfs:DefaultSRS/text()", nsContext, null );
312                otherSrs = XMLTools.getNodesAsURIs( element, "wfs:OtherSRS/text()", nsContext );
313            }
314    
315            org.deegree.ogcwebservices.wfs.capabilities.Operation[] operations = null;
316            Element operationsTypeElement = (Element) XMLTools.getNode( element, "wfs:Operations", nsContext );
317            if ( operationsTypeElement != null ) {
318                operations = getOperationsType( operationsTypeElement );
319            }
320            List<Element> formatElementList = XMLTools.getElements( element, "wfs:OutputFormats/wfs:Format", nsContext );
321            FormatType[] formats = new FormatType[formatElementList.size()];
322            for ( int i = 0; i < formats.length; i++ ) {
323                formats[i] = getFormatType( formatElementList.get( i ) );
324            }
325            List<Element> wgs84BoundingBoxElements = XMLTools.getElements( element, "ows:WGS84BoundingBox", nsContext );
326            if ( wgs84BoundingBoxElements.size() < 1 ) {
327                throw new XMLParsingException( "A 'wfs:FeatureTypeType' must contain at least one "
328                                               + "'ows:WGS84BoundingBox'-element." );
329            }
330            Envelope[] wgs84BoundingBoxes = new Envelope[wgs84BoundingBoxElements.size()];
331            for ( int i = 0; i < wgs84BoundingBoxes.length; i++ ) {
332                wgs84BoundingBoxes[i] = getWGS84BoundingBoxType( wgs84BoundingBoxElements.get( i ) );
333            }
334            List<Element> metadataURLElementList = XMLTools.getElements( element, "wfs:MetadataURL", nsContext );
335            MetadataURL[] metadataUrls = new MetadataURL[metadataURLElementList.size()];
336            for ( int i = 0; i < metadataUrls.length; i++ ) {
337                metadataUrls[i] = getMetadataURL( metadataURLElementList.get( i ) );
338            }
339            WFSFeatureType featureType = new WFSFeatureType( name, title, abstract_, keywords, defaultSrs, otherSrs,
340                                                             operations, formats, wgs84BoundingBoxes, metadataUrls );
341    
342            return featureType;
343        }
344    }