001    //$HeadURL: $
002    /*----------------    FILE HEADER  ------------------------------------------
003     This file is part of deegree.
004     Copyright (C) 2001-2008 by:
005     Department of Geography, University of Bonn
006     http://www.giub.uni-bonn.de/deegree/
007     lat/lon GmbH
008     http://www.lat-lon.de
009    
010     This library is free software; you can redistribute it and/or
011     modify it under the terms of the GNU Lesser General Public
012     License as published by the Free Software Foundation; either
013     version 2.1 of the License, or (at your option) any later version.
014     This library is distributed in the hope that it will be useful,
015     but WITHOUT ANY WARRANTY; without even the implied warranty of
016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017     Lesser General Public License for more details.
018     You should have received a copy of the GNU Lesser General Public
019     License along with this library; if not, write to the Free Software
020     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021     Contact:
022    
023     Andreas Poth
024     lat/lon GmbH
025     Aennchenstr. 19
026     53177 Bonn
027     Germany
028     E-Mail: poth@lat-lon.de
029    
030     Prof. Dr. Klaus Greve
031     Department of Geography
032     University of Bonn
033     Meckenheimer Allee 166
034     53115 Bonn
035     Germany
036     E-Mail: greve@giub.uni-bonn.de
037     ---------------------------------------------------------------------------*/
038    
039    package org.deegree.ogcwebservices.wcts.capabilities;
040    
041    import static org.deegree.framework.xml.XMLTools.getElement;
042    import static org.deegree.framework.xml.XMLTools.getElements;
043    import static org.deegree.framework.xml.XMLTools.getNodeAsBoolean;
044    import static org.deegree.framework.xml.XMLTools.getNodesAsStringList;
045    import static org.deegree.framework.xml.XMLTools.getRequiredElements;
046    import static org.deegree.framework.xml.XMLTools.getRequiredNodeAsBoolean;
047    import static org.deegree.ogcbase.CommonNamespaces.WCS_1_2_0_PREFIX;
048    import static org.deegree.ogcbase.CommonNamespaces.WCTS_PREFIX;
049    
050    import java.util.ArrayList;
051    import java.util.List;
052    
053    import org.deegree.framework.log.ILogger;
054    import org.deegree.framework.log.LoggerFactory;
055    import org.deegree.framework.util.Pair;
056    import org.deegree.framework.xml.XMLParsingException;
057    import org.deegree.framework.xml.XMLTools;
058    import org.deegree.model.crs.CRSFactory;
059    import org.deegree.model.crs.CoordinateSystem;
060    import org.deegree.model.crs.UnknownCRSException;
061    import org.deegree.ogcbase.CommonNamespaces;
062    import org.deegree.ogcbase.ExceptionCode;
063    import org.deegree.ogcwebservices.getcapabilities.InvalidCapabilitiesException;
064    import org.deegree.ogcwebservices.getcapabilities.OGCCapabilities;
065    import org.deegree.owscommon_1_1_0.OWSCommonCapabilitiesDocument;
066    import org.w3c.dom.Element;
067    
068    /**
069     * <code>WCTSCapabilitiesDocument</code> parses a given wcts:Capabilities document version 0.4.0, with ows:Common
070     * 1.1.0 and csw 1.2.0.
071     * 
072     * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
073     * 
074     * @author last edited by: $Author:$
075     * 
076     * @version $Revision:$, $Date:$
077     * 
078     */
079    public class WCTSCapabilitiesDocument extends OWSCommonCapabilitiesDocument {
080    
081        /**
082         * 
083         */
084        private static final long serialVersionUID = -2378224055294207801L;
085    
086        private static ILogger LOG = LoggerFactory.getLogger( WCTSCapabilitiesDocument.class );
087    
088        private static String PRE = WCTS_PREFIX + ":";
089    
090        // Default value of codeType attribute, from wctsCommon.xsd.
091        private static String DEFAULT_COV_URL = "http://schemas.opengis.net/wcts/0.0.0/coverageType.xml";
092    
093        private static String DEFAULT_GEOM_URL = "http://schemas.opengis.net/wcts/0.0.0/geometryType.xml";
094    
095        /**
096         * Creates a wcts 0.4.0 capabilities document with the rootnode set to wcts:Capabilities.
097         */
098        public void createEmptyDocument() {
099            setRootElement( XMLTools.create().createElementNS( CommonNamespaces.WCTSNS.toASCIIString(),
100                                                               PRE + "Capabilities" ) );
101        }
102    
103        /*
104         * (non-Javadoc)
105         * 
106         * @see org.deegree.ogcwebservices.getcapabilities.OGCCapabilitiesDocument#parseCapabilities()
107         */
108        @Override
109        public OGCCapabilities parseCapabilities()
110                                                  throws InvalidCapabilitiesException {
111            WCTSCapabilities caps = null;
112            try {
113                caps = new WCTSCapabilities( parseVersion(),
114                                             parseUpdateSequence(),
115                                             parseServiceIdentification(),
116                                             parseServiceProvider(),
117                                             parseOperationsMetadata(),
118                                             parseContents() );
119            } catch ( XMLParsingException e ) {
120                LOG.logError( e.getMessage(), e );
121                throw new InvalidCapabilitiesException( e.getMessage(), ExceptionCode.INVALID_FORMAT );
122            } catch ( UnknownCRSException ucrse ) {
123                LOG.logError( ucrse.getMessage(), ucrse );
124                throw new InvalidCapabilitiesException( ucrse.getMessage(), ExceptionCode.INVALID_FORMAT );
125            }
126            return caps;
127        }
128    
129        /**
130         * Parses the optional wcts:Content element of the wcts:Capabilities element.
131         * 
132         * @return
133         * @throws XMLParsingException
134         * @throws UnknownCRSException
135         */
136        protected Content parseContents()
137                                       throws XMLParsingException, UnknownCRSException {
138            Element contents = getElement( getRootElement(), PRE + "Contents", nsContext );
139            if ( contents == null ) {
140                return null;
141            }
142            List<String> transformations = getNodesAsStringList( contents, PRE + "Transformation", nsContext );
143            List<String> methods = getNodesAsStringList( contents, PRE + "Method", nsContext );
144            List<String> sCRSs = getNodesAsStringList( contents, PRE + "SourceCRS", nsContext );
145            if ( sCRSs == null || sCRSs.size() == 0 ) {
146                throw new XMLParsingException( "The " + PRE
147                                               + "Content node of the "
148                                               + PRE
149                                               + "Capabilites must have at least one SourceCRS element." );
150            }
151            List<CoordinateSystem> sourceCRSs = new ArrayList<CoordinateSystem>( sCRSs.size() );
152            for ( String crs : sCRSs ) {
153                sourceCRSs.add( CRSFactory.create( crs ) );
154            }
155    
156            List<String> tCRSs = getNodesAsStringList( contents, PRE + "TargetCRS", nsContext );
157            if ( tCRSs == null || tCRSs.size() == 0 ) {
158                throw new XMLParsingException( "The " + PRE
159                                               + "Content node of the "
160                                               + PRE
161                                               + "Capabilites must have at least one TargetCRS element." );
162            }
163    
164            List<CoordinateSystem> targetCRSs = new ArrayList<CoordinateSystem>( tCRSs.size() );
165            for ( String crs : tCRSs ) {
166                targetCRSs.add( CRSFactory.create( crs ) );
167            }
168            CoverageAbilities coverageAbilities = parseCoverageAbilities( getElement( contents,
169                                                                                      PRE + "CoverageAbilities",
170                                                                                      nsContext ) );
171            FeatureAbilities featureAbilities = parseFeatureAbilities( getElement( contents,
172                                                                                   PRE + "FeatureAbilities",
173                                                                                   nsContext ) );
174            if ( coverageAbilities == null && featureAbilities == null ) {
175                throw new XMLParsingException( "Both the " + PRE
176                                               + "CoverageAbilities and "
177                                               + PRE
178                                               + "FeatureAbilities elements are null, at least one must be present in the "
179                                               + PRE
180                                               + "Content element of the WCTS-capabilities document." );
181            }
182    
183            List<Pair<String, String>> metadata = parseMetadatas( getElements( contents, PRE_OWS + "Metadata", nsContext ) );
184    
185            boolean userDefinedCRS = getRequiredNodeAsBoolean( contents, "@userDefinedCRSs", nsContext );
186    
187            return new Content( transformations,
188                                methods,
189                                sourceCRSs,
190                                targetCRSs,
191                                coverageAbilities,
192                                featureAbilities,
193                                metadata,
194                                userDefinedCRS );
195        }
196    
197        /**
198         * @param element
199         * @return
200         * @throws XMLParsingException
201         */
202        private FeatureAbilities parseFeatureAbilities( Element element )
203                                                                         throws XMLParsingException {
204            if ( element == null ) {
205                return null;
206            }
207            List<Element> requiredElements = getRequiredElements( element, PRE + "GeometryType", nsContext );
208            List<Pair<String, String>> featureTypes = new ArrayList<Pair<String, String>>( requiredElements.size() );
209            for ( Element geomElement : requiredElements ) {
210                Pair<String, String> t = parseCodeType( geomElement, DEFAULT_GEOM_URL );
211                if ( t != null ) {
212                    featureTypes.add( t );
213                }
214            }
215    
216            requiredElements = getRequiredElements( element, PRE + "FeatureFormat", nsContext );
217            List<InputOutputFormat> featureFormats = new ArrayList<InputOutputFormat>( requiredElements.size() );
218            for ( Element featureFormElement : requiredElements ) {
219                InputOutputFormat t = parseInputOutputFormatType( featureFormElement );
220                if ( t != null ) {
221                    featureFormats.add( t );
222                }
223            }
224    
225            boolean remoteProperties = getRequiredNodeAsBoolean( element, "@remoteProperties", nsContext );
226    
227            return new FeatureAbilities( featureTypes, featureFormats, remoteProperties );
228        }
229    
230        /**
231         * Parses given element for coverageType, CoverageFormat and InterpolatinMethods, the latter is not evaluated yet
232         * though.
233         * 
234         * @param caElement
235         * @return
236         * @throws XMLParsingException
237         */
238        private CoverageAbilities parseCoverageAbilities( Element caElement )
239                                                                             throws XMLParsingException {
240            if ( caElement == null ) {
241                return null;
242            }
243            List<Element> ctElements = getRequiredElements( caElement, PRE + "CoverageType", nsContext );
244            List<Pair<String, String>> coverageTypes = new ArrayList<Pair<String, String>>( ctElements.size() );
245            for ( Element ct : ctElements ) {
246                Pair<String, String> t = parseCodeType( ct, DEFAULT_COV_URL );
247                if ( t != null ) {
248                    coverageTypes.add( t );
249                }
250            }
251            ctElements = getRequiredElements( caElement, PRE + "CoverageFormat", nsContext );
252            List<InputOutputFormat> coverageFormats = new ArrayList<InputOutputFormat>( ctElements.size() );
253            for ( Element ct : ctElements ) {
254                InputOutputFormat t = parseInputOutputFormatType( ct );
255                if ( t != null ) {
256                    coverageFormats.add( t );
257                }
258            }
259            List<Element> interPolationMethods = getRequiredElements( caElement,
260                                                                      WCS_1_2_0_PREFIX + ":InterpolationMethods",
261                                                                      nsContext );
262            LOG.logWarning( "The " + WCS_1_2_0_PREFIX + ":InterpolationMethods are not evaluated yet." );
263            return new CoverageAbilities( coverageTypes, coverageFormats, interPolationMethods );
264        }
265    
266        /**
267         * return the <value,codetype> pair of a CodeType element.
268         * 
269         * @param elem
270         *            to parse from
271         * @param defaultString
272         *            the String to use as a default value.
273         * @return the <text(), codeType-attribute> pair or <code>null</code> if the element is <code>null</code>
274         */
275        private Pair<String, String> parseCodeType( Element elem, String defaultString ) {
276            String value = elem.getTextContent();
277            String attrib = elem.getAttribute( "codeSpace" );
278            if ( attrib == null || "".equals( attrib ) ) {
279                attrib = defaultString;
280            }
281            return new Pair<String, String>( value, attrib );
282        }
283    
284        /**
285         * return the <mimetype,<input,output>> pair of a CodeType element.
286         * 
287         * @param elem
288         *            to parse from
289         * @return the <text(), <input,output>> pair or <code>null</code> if the element is <code>null</code>
290         * @throws XMLParsingException
291         */
292        private InputOutputFormat parseInputOutputFormatType( Element elem )
293                                                                            throws XMLParsingException {
294            String value = elem.getTextContent();
295            boolean input = getNodeAsBoolean( elem, "@input", nsContext, true );
296            boolean output = getNodeAsBoolean( elem, "@output", nsContext, true );
297            return new InputOutputFormat( value, input, output );
298        }
299    
300    }