001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/ogcwebservices/wms/capabilities/WMSCapabilitiesDocument_1_3_0.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003     This file is part of deegree.
004     Copyright (C) 2001-2006 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     This library is free software; you can redistribute it and/or
010     modify it under the terms of the GNU Lesser General Public
011     License as published by the Free Software Foundation; either
012     version 2.1 of the License, or (at your option) any later version.
013     This library is distributed in the hope that it will be useful,
014     but WITHOUT ANY WARRANTY; without even the implied warranty of
015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016     Lesser General Public License for more details.
017     You should have received a copy of the GNU Lesser General Public
018     License along with this library; if not, write to the Free Software
019     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020     Contact:
021     Andreas Poth
022     lat/lon GmbH
023     Aennchenstraße 19
024     53177 Bonn
025     Germany
026     E-Mail: poth@lat-lon.de
027     Jens Fitzke
028     lat/lon GmbH
029     Aennchenstraße 19
030     53177 Bonn
031     Germany
032     E-Mail: jens.fitzke@uni-bonn.de
033     ---------------------------------------------------------------------------*/
034    package org.deegree.ogcwebservices.wms.capabilities;
035    
036    import java.io.IOException;
037    import java.net.MalformedURLException;
038    import java.net.URI;
039    import java.net.URISyntaxException;
040    import java.net.URL;
041    import java.util.ArrayList;
042    import java.util.Arrays;
043    import java.util.Date;
044    import java.util.List;
045    
046    import org.deegree.datatypes.Code;
047    import org.deegree.datatypes.QualifiedName;
048    import org.deegree.datatypes.values.TypedLiteral;
049    import org.deegree.framework.log.ILogger;
050    import org.deegree.framework.log.LoggerFactory;
051    import org.deegree.framework.util.StringTools;
052    import org.deegree.framework.xml.XMLParsingException;
053    import org.deegree.framework.xml.XMLTools;
054    import org.deegree.i18n.Messages;
055    import org.deegree.model.crs.CRSFactory;
056    import org.deegree.model.crs.CoordinateSystem;
057    import org.deegree.model.crs.UnknownCRSException;
058    import org.deegree.model.metadata.iso19115.Address;
059    import org.deegree.model.metadata.iso19115.CitedResponsibleParty;
060    import org.deegree.model.metadata.iso19115.Constraints;
061    import org.deegree.model.metadata.iso19115.ContactInfo;
062    import org.deegree.model.metadata.iso19115.Keywords;
063    import org.deegree.model.metadata.iso19115.Linkage;
064    import org.deegree.model.metadata.iso19115.OnlineResource;
065    import org.deegree.model.metadata.iso19115.Phone;
066    import org.deegree.model.spatialschema.Envelope;
067    import org.deegree.model.spatialschema.GeometryFactory;
068    import org.deegree.model.spatialschema.Position;
069    import org.deegree.ogcbase.CommonNamespaces;
070    import org.deegree.ogcwebservices.getcapabilities.InvalidCapabilitiesException;
071    import org.deegree.ogcwebservices.getcapabilities.MetadataURL;
072    import org.deegree.ogcwebservices.getcapabilities.OGCCapabilities;
073    import org.deegree.owscommon_new.DCP;
074    import org.deegree.owscommon_new.DomainType;
075    import org.deegree.owscommon_new.HTTP;
076    import org.deegree.owscommon_new.Operation;
077    import org.deegree.owscommon_new.OperationsMetadata;
078    import org.deegree.owscommon_new.Parameter;
079    import org.deegree.owscommon_new.ServiceIdentification;
080    import org.deegree.owscommon_new.ServiceProvider;
081    import org.w3c.dom.Element;
082    import org.w3c.dom.Node;
083    import org.xml.sax.SAXException;
084    
085    /**
086     * <code>WMSCapabilitiesDocument_1_3_0</code> is a parser class for capabilities documents
087     * according to the OGC WMS 1.3.0 specification.
088     * 
089     * @author <a href="mailto:schmitz@lat-lon.de">Andreas Schmitz</a>
090     * @author last edited by: $Author: aschmitz $
091     * 
092     * @version 2.0, $Revision: 6891 $, $Date: 2007-05-08 14:02:55 +0200 (Di, 08 Mai 2007) $
093     * 
094     * @since 2.0
095     */
096    
097    public class WMSCapabilitiesDocument_1_3_0 extends WMSCapabilitiesDocument {
098    
099        private static final long serialVersionUID = -5085466301546020723L;
100    
101        private static final String XML_TEMPLATE = "WMSCapabilitiesTemplate_1_3_0.xml";
102    
103        private static final ILogger LOG = LoggerFactory.getLogger( WMSCapabilitiesDocument_1_3_0.class );
104    
105        private static final String PWMS = CommonNamespaces.WMS_PREFIX + ":";
106    
107        private static final String PSLD = CommonNamespaces.SLD_PREFIX + ":";
108    
109        /*
110         * Just using a different XML_TEMPLATE.
111         */
112        @Override
113        public void createEmptyDocument()
114                                throws IOException, SAXException {
115    
116            URL url = WMSCapabilitiesDocument.class.getResource( XML_TEMPLATE );
117            if ( url == null ) {
118                throw new IOException( "The resource '" + XML_TEMPLATE + " could not be found." );
119            }
120            load( url );
121        }
122    
123        /*
124         * Prefix added, not parsing UserDefinedSymbolization. Parsing new LayerLimit, MaxWidth,
125         * MaxHeight elements.
126         */
127        @Override
128        public OGCCapabilities parseCapabilities()
129                                throws InvalidCapabilitiesException {
130            ServiceIdentification serviceIdentification = null;
131            ServiceProvider serviceProvider = null;
132            OperationsMetadata metadata = null;
133            Layer layer = null;
134            String version = parseVersion();
135            String updateSeq = parseUpdateSequence();
136    
137            Element root = getRootElement();
138    
139            int layerLimit = 0;
140            int maxWidth = 0;
141            int maxHeight = 0;
142    
143            try {
144                Element serviceElement = (Element) XMLTools.getRequiredNode( root, PWMS + "Service", nsContext );
145    
146                layerLimit = XMLTools.getNodeAsInt( serviceElement, PWMS + "LayerLimit", nsContext, 0 );
147                maxWidth = XMLTools.getNodeAsInt( serviceElement, PWMS + "MaxWidth", nsContext, 0 );
148                maxHeight = XMLTools.getNodeAsInt( serviceElement, PWMS + "MaxHeight", nsContext, 0 );
149    
150                serviceIdentification = parseServiceIdentification();
151                serviceProvider = parseServiceProvider();
152                metadata = parseOperationsMetadata();
153    
154                Element layerElem = (Element) XMLTools.getRequiredNode( root, PWMS + "Capability/" + PWMS + "Layer",
155                                                                        nsContext );
156                layer = parseLayers( layerElem, null, null );
157            } catch ( XMLParsingException e ) {
158                LOG.logError( e.getLocalizedMessage(), e );
159                throw new InvalidCapabilitiesException( e.getMessage() + StringTools.stackTraceToString( e ) );
160            } catch ( Exception e ) {
161                LOG.logError( e.getLocalizedMessage(), e );
162                throw new InvalidCapabilitiesException( e.getMessage() + StringTools.stackTraceToString( e ) );
163            }
164    
165            WMSCapabilities_1_3_0 wmsCapabilities = new WMSCapabilities_1_3_0( version, updateSeq, serviceIdentification,
166                                                                               serviceProvider, metadata, layer,
167                                                                               layerLimit, maxWidth, maxHeight );
168            return wmsCapabilities;
169        }
170    
171        /*
172         * Prefix added. Name is now "WMS" instead of "OGC:WMS"
173         */
174        @Override
175        protected ServiceIdentification parseServiceIdentification()
176                                throws XMLParsingException {
177    
178            String name = XMLTools.getNodeAsString( getRootElement(), PWMS + "Service/" + PWMS + "Name", nsContext, null );
179            String title = XMLTools.getNodeAsString( getRootElement(), PWMS + "Service/" + PWMS + "Title", nsContext, name );
180            String serviceAbstract = XMLTools.getNodeAsString( getRootElement(), PWMS + "Service/" + PWMS + "Abstract",
181                                                               nsContext, null );
182    
183            String[] kw = XMLTools.getNodesAsStrings( getRootElement(), PWMS + "Service/" + PWMS + "KeywordList/" + PWMS
184                                                                        + "Keyword", nsContext );
185    
186            Keywords[] keywordArray = new Keywords[] { new Keywords( kw ) };
187            List<Keywords> keywords = Arrays.asList( keywordArray );
188    
189            String fees = XMLTools.getNodeAsString( getRootElement(), PWMS + "Service/" + PWMS + "Fees", nsContext, null );
190    
191            List<Constraints> accessConstraints = new ArrayList<Constraints>();
192    
193            String[] constraints = XMLTools.getNodesAsStrings( getRootElement(), PWMS + "Service/" + PWMS
194                                                                                 + "AccessConstraints", nsContext );
195    
196            for ( String constraint : constraints ) {
197                List<String> limits = new ArrayList<String>();
198                limits.add( constraint );
199                accessConstraints.add( new Constraints( fees, null, null, null, limits, null, null, null ) );
200            }
201    
202            List<String> versions = new ArrayList<String>();
203            versions.add( "1.0.0" );
204            versions.add( "1.1.0" );
205            versions.add( "1.1.1" );
206            versions.add( "1.2.0" );
207            versions.add( "1.3.0" );
208    
209            ServiceIdentification serviceIdentification = new ServiceIdentification(
210                                                                                     new Code( "WMS" ),
211                                                                                     versions,
212                                                                                     title,
213                                                                                     null,
214                                                                                     new Date( System.currentTimeMillis() ),
215                                                                                     title, serviceAbstract, keywords,
216                                                                                     accessConstraints );
217            LOG.exiting();
218            return serviceIdentification;
219        }
220    
221        /*
222         * Prefix added.
223         */
224        @Override
225        protected ServiceProvider parseServiceProvider()
226                                throws XMLParsingException {
227            Node ci = XMLTools.getNode( getRootElement(), PWMS + "Service/" + PWMS + "ContactInformation", nsContext );
228    
229            // according to WMS 1.1.1 specification this element is mandatory
230            // but there are several services online which does not contain
231            // this element in its capabilities :-(
232            String s = XMLTools.getNodeAsString( getRootElement(), PWMS + "Service/" + PWMS + "OnlineResource/@xlink:href",
233                                                 nsContext, null );
234    
235            OnlineResource providerSite = null;
236    
237            if ( s != null ) {
238                try {
239                    providerSite = new OnlineResource( new Linkage( new URL( s ) ) );
240                } catch ( MalformedURLException e ) {
241                    throw new XMLParsingException( "could not parse service online resource", e );
242                }
243            } else {
244                // use default if no online resource is contained in the
245                // capabilities (see comment above)
246                try {
247                    providerSite = new OnlineResource( new Linkage( new URL( "http://www.opengeospatial.org/" ) ) );
248                } catch ( MalformedURLException neverHappens ) {
249                    // useless exception
250                }
251            }
252    
253            String person = null;
254            String orga = null;
255            String position = null;
256            if ( ci != null ) {
257                person = XMLTools.getNodeAsString( ci, PWMS + "ContactPersonPrimary/" + PWMS + "ContactPerson", nsContext,
258                                                   null );
259                orga = XMLTools.getNodeAsString( ci, PWMS + "ContactPersonPrimary/" + PWMS + "ContactOrganization",
260                                                 nsContext, null );
261                position = XMLTools.getNodeAsString( ci, PWMS + "ContactPosition", nsContext, null );
262            }
263            ContactInfo contact = parseContactInfo();
264    
265            CitedResponsibleParty party = new CitedResponsibleParty( new ContactInfo[] { contact },
266                                                                     new String[] { person }, new String[] { orga },
267                                                                     new String[] { position }, null );
268            ServiceProvider sp = new ServiceProvider( person, providerSite, party );
269    
270            return sp;
271        }
272    
273        /*
274         * Prefix added.
275         */
276        @Override
277        protected ContactInfo parseContactInfo()
278                                throws XMLParsingException {
279            Node ci = XMLTools.getNode( getRootElement(), PWMS + "Service/" + PWMS + "ContactInformation", nsContext );
280            ContactInfo cont = null;
281            if ( ci != null ) {
282                String[] addr = XMLTools.getNodesAsStrings( ci, PWMS + "ContactAddress/" + PWMS + "Address", nsContext );
283                // String addrType =
284                // XMLTools.getNodeAsString( ci, "./ContactAddress/AddressType", nsContext, null );
285                String city = XMLTools.getNodeAsString( ci, PWMS + "ContactAddress/" + PWMS + "City", nsContext, null );
286                String state = XMLTools.getNodeAsString( ci, PWMS + "ContactAddress/" + PWMS + "StateOrProvince",
287                                                         nsContext, null );
288                String pc = XMLTools.getNodeAsString( ci, PWMS + "ContactAddress/" + PWMS + "PostCode", nsContext, null );
289                String country = XMLTools.getNodeAsString( ci, PWMS + "ContactAddress/" + PWMS + "Country", nsContext, null );
290                String[] mail = XMLTools.getNodesAsStrings( ci, PWMS + "ContactElectronicMailAddress", nsContext );
291                Address address = new Address( state, city, country, addr, mail, pc );
292    
293                String[] phone = XMLTools.getNodesAsStrings( ci, PWMS + "ContactVoiceTelephone", nsContext );
294                String[] fax = XMLTools.getNodesAsStrings( ci, PWMS + "ContactFacsimileTelephone", nsContext );
295    
296                Phone ph = new Phone( fax, phone );
297    
298                cont = new ContactInfo( address, null, null, null, ph );
299            }
300    
301            return cont;
302        }
303    
304        /*
305         * Prefix added.
306         */
307        @Override
308        protected OperationsMetadata parseOperationsMetadata()
309                                throws XMLParsingException {
310    
311            Node opNode = XMLTools.getNode( getRootElement(), PWMS + "Capability/" + PWMS + "Request/" + PWMS
312                                                              + "GetCapabilities", nsContext );
313    
314            if ( opNode == null ) {
315                // may it is a WMS 1.0.0 capabilities document
316                opNode = XMLTools.getRequiredNode( getRootElement(), PWMS + "Capability/" + PWMS + "Request/" + PWMS
317                                                                     + "Capabilities", nsContext );
318            }
319            Operation getCapa = parseOperation( opNode );
320    
321            opNode = XMLTools.getNode( getRootElement(), PWMS + "Capability/" + PWMS + "Request/" + PWMS + "GetMap",
322                                       nsContext );
323            if ( opNode == null ) {
324                // may it is a WMS 1.0.0 capabilities document
325                opNode = XMLTools.getRequiredNode( getRootElement(), PWMS + "Capability/" + PWMS + "Request/" + PWMS
326                                                                     + "Map", nsContext );
327            }
328            Operation getMap = parseOperation( opNode );
329    
330            opNode = XMLTools.getNode( getRootElement(),
331                                       PWMS + "Capability/" + PWMS + "Request/" + PWMS + "GetFeatureInfo", nsContext );
332            Operation getFI = null;
333            if ( opNode != null ) {
334                getFI = parseOperation( opNode );
335            } else {
336                // maybe its WMS 1.0.0
337                opNode = XMLTools.getNode( getRootElement(), PWMS + "Capability/" + PWMS + "Request/" + PWMS
338                                                             + "FeatureInfo", nsContext );
339                if ( opNode != null ) {
340                    getFI = parseOperation( opNode );
341                }
342            }
343    
344            opNode = XMLTools.getNode( getRootElement(), PWMS + "Capability/" + PWMS + "Request/" + PSLD
345                                                         + "GetLegendGraphic", nsContext );
346            Operation getLG = null;
347            if ( opNode != null ) {
348                getLG = parseOperation( opNode );
349            }
350    
351            opNode = XMLTools.getNode( getRootElement(), PWMS + "Capability/" + PWMS + "Request/" + PWMS + "DescribeLayer",
352                                       nsContext );
353            Operation descL = null;
354            if ( opNode != null ) {
355                descL = parseOperation( opNode );
356            }
357    
358            opNode = XMLTools.getNode( getRootElement(), PWMS + "Capability/" + PWMS + "Request/" + PSLD + "GetStyles",
359                                       nsContext );
360            Operation getStyles = null;
361            if ( opNode != null ) {
362                getStyles = parseOperation( opNode );
363            }
364    
365            opNode = XMLTools.getNode( getRootElement(), PWMS + "Capability/" + PWMS + "Request/" + PSLD + "PutStyles",
366                                       nsContext );
367            Operation putStyles = null;
368            if ( opNode != null ) {
369                putStyles = parseOperation( opNode );
370            }
371    
372            List<Operation> operations = new ArrayList<Operation>();
373    
374            StringBuffer debug = new StringBuffer();
375    
376            if ( getCapa != null ) {
377                operations.add( getCapa );
378                debug.append( " GetCapabilities" );
379            }
380            if ( getMap != null ) {
381                operations.add( getMap );
382                debug.append( " GetMap" );
383            }
384            if ( getFI != null ) {
385                operations.add( getFI );
386                debug.append( " GetFeatureInfo" );
387            }
388            if ( getLG != null ) {
389                operations.add( getLG );
390                debug.append( " GetLegendGraphic" );
391            }
392            if ( descL != null ) {
393                operations.add( descL );
394                debug.append( " DescribeLayer" );
395            }
396            if ( getStyles != null ) {
397                operations.add( getStyles );
398                debug.append( " GetStyles" );
399            }
400            if ( putStyles != null ) {
401                operations.add( putStyles );
402                debug.append( " PutStyles" );
403            }
404    
405            LOG.logDebug( "Configured request types:" + debug );
406    
407            OperationsMetadata metadata = new OperationsMetadata( null, null, operations, null );
408    
409            return metadata;
410        }
411    
412        /*
413         * Prefix added.
414         */
415        @Override
416        protected Operation parseOperation( Node node )
417                                throws XMLParsingException {
418            // use node name as name of the Operation to be defined
419            String name = node.getNodeName();
420            if ( name.equals( "Capabilities" ) ) {
421                name = "GetCapabilities";
422            } else if ( name.equals( "Map" ) ) {
423                name = "GetMap";
424            } else if ( name.equals( "FeatureInfo" ) ) {
425                name = "GetFeatureInfo";
426            }
427    
428            String[] tmp = XMLTools.getRequiredNodesAsStrings( node, PWMS + "Format", nsContext );
429            List<TypedLiteral> values = new ArrayList<TypedLiteral>();
430    
431            URI stringURI = null;
432            try {
433                stringURI = new URI( null, "String", null );
434            } catch ( URISyntaxException e ) {
435                // cannot happen, why do I have to catch this?
436            }
437    
438            for ( String str : tmp )
439                values.add( new TypedLiteral( str, stringURI ) );
440    
441            DomainType owsDomainType = new DomainType( false, true, null, 0, new QualifiedName( "Format" ), values, null,
442                                                       null, false, null, false, null, null, null, null );
443            List<Parameter> parameters = new ArrayList<Parameter>();
444            parameters.add( owsDomainType );
445    
446            List<?> nl = XMLTools.getRequiredNodes( node, PWMS + "DCPType", nsContext );
447            List<DCP> dcps = new ArrayList<DCP>();
448    
449            for ( Object element : nl ) {
450                dcps.add( parseDCP( (Element) element ) );
451            }
452    
453            return new Operation( new QualifiedName( name ), dcps, parameters, null, null, null );
454        }
455    
456        /*
457         * Prefix added.
458         */
459        @Override
460        protected DCP parseDCP( Element element )
461                                throws XMLParsingException {
462            List<HTTP.Type> types = new ArrayList<HTTP.Type>();
463            List<OnlineResource> links = new ArrayList<OnlineResource>();
464    
465            Element elem = (Element) XMLTools.getRequiredNode( element, PWMS + "HTTP", nsContext );
466            String s = null;
467            try {
468                List<?> nl = XMLTools.getNodes( elem, PWMS + "Get", nsContext );
469    
470                for ( int i = 0; i < nl.size(); i++ ) {
471                    s = XMLTools.getNodeAsString( (Node) nl.get( i ), "./@xlink:href", nsContext, null );
472                    if ( s == null ) {
473                        s = XMLTools.getRequiredNodeAsString( (Node) nl.get( i ), PWMS + "OnlineResource/@xlink:href",
474                                                              nsContext );
475                    }
476                    types.add( HTTP.Type.Get );
477                    links.add( new OnlineResource( new Linkage( new URL( s ) ) ) );
478                }
479            } catch ( Exception e ) {
480                throw new XMLParsingException( Messages.getMessage( "WMS_DCPGET", s ) );
481            }
482            try {
483                List<?> nl = XMLTools.getNodes( elem, PWMS + "Post", nsContext );
484    
485                for ( int i = 0; i < nl.size(); i++ ) {
486                    s = XMLTools.getNodeAsString( (Node) nl.get( i ), "./@xlink:href", nsContext, null );
487                    if ( s == null ) {
488                        s = XMLTools.getRequiredNodeAsString( (Node) nl.get( i ), PWMS + "OnlineResource/@xlink:href",
489                                                              nsContext );
490                    }
491                    types.add( HTTP.Type.Post );
492                    links.add( new OnlineResource( new Linkage( new URL( s ) ) ) );
493                }
494    
495            } catch ( MalformedURLException e ) {
496                throw new XMLParsingException( Messages.getMessage( "WMS_DCPPOST", s ) );
497            }
498            HTTP http = new HTTP( links, null, types );
499    
500            return http;
501        }
502    
503        /*
504         * Prefix added. Removed parsing of Extent. Removed parsing of ScaleHint. Changed SRS to CRS.
505         */
506        @Override
507        protected Layer parseLayers( Element layerElem, Layer parent, ScaleHint scaleHint )
508                                throws XMLParsingException, UnknownCRSException {
509    
510            boolean queryable = XMLTools.getNodeAsBoolean( layerElem, "./@queryable", nsContext, false );
511    
512            int cascaded = XMLTools.getNodeAsInt( layerElem, "./@cascaded", nsContext, 0 );
513            boolean opaque = XMLTools.getNodeAsBoolean( layerElem, "./@opaque", nsContext, false );
514            boolean noSubsets = XMLTools.getNodeAsBoolean( layerElem, "./@noSubsets", nsContext, false );
515            int fixedWidth = XMLTools.getNodeAsInt( layerElem, "./@fixedWidth", nsContext, 0 );
516            int fixedHeight = XMLTools.getNodeAsInt( layerElem, "./@fixedHeight", nsContext, 0 );
517            String name = XMLTools.getNodeAsString( layerElem, PWMS + "Name", nsContext, null );
518            String title = XMLTools.getRequiredNodeAsString( layerElem, PWMS + "Title", nsContext );
519            String layerAbstract = XMLTools.getNodeAsString( layerElem, PWMS + "Abstract", nsContext, null );
520            String[] keywords = XMLTools.getNodesAsStrings( layerElem, PWMS + "KeywordList/" + PWMS + "Keyword", nsContext );
521            String[] srs = XMLTools.getNodesAsStrings( layerElem, PWMS + "CRS", nsContext );
522    
523            List<Element> nl = XMLTools.getElements( layerElem, PWMS + "BoundingBox", nsContext );
524            // TODO
525            // substitue with Envelope
526            LayerBoundingBox[] bboxes = null;
527            if ( nl.size() == 0 && parent != null ) {
528                // inherit BoundingBoxes from parent layer
529                bboxes = parent.getBoundingBoxes();
530            } else {
531                bboxes = parseLayerBoundingBoxes( nl );
532            }
533    
534            Element llBox = (Element) XMLTools.getNode( layerElem, PWMS + "EX_GeographicBoundingBox", nsContext );
535            Envelope llBoundingBox = null;
536    
537            if ( llBox == null && parent != null ) {
538                // inherit LatLonBoundingBox parent layer
539                llBoundingBox = parent.getLatLonBoundingBox();
540            } else if ( llBox != null ) {
541                llBoundingBox = parseEX_GeographicBoundingBox( llBox );
542            } else {
543                llBoundingBox = GeometryFactory.createEnvelope( -180, -90, 180, 90, CRSFactory.create( "EPSG:4326" ) );
544            }
545    
546            Dimension[] dimensions = parseDimensions( layerElem );
547    
548            Attribution attribution = parseAttribution( layerElem );
549    
550            AuthorityURL[] authorityURLs = parseAuthorityURLs( layerElem );
551    
552            MetadataURL[] metadataURLs = parseMetadataURLs( layerElem );
553    
554            DataURL[] dataURLs = parseDataURL( layerElem );
555    
556            Identifier[] identifiers = parseIdentifiers( layerElem );
557    
558            FeatureListURL[] featureListURLs = parseFeatureListURL( layerElem );
559    
560            Style[] styles = parseStyles( layerElem );
561    
562            scaleHint = parseScaleHint( layerElem, scaleHint );
563    
564            Layer layer = new Layer( queryable, cascaded, opaque, noSubsets, fixedWidth, fixedHeight, name, title,
565                                     layerAbstract, llBoundingBox, attribution, scaleHint, keywords, srs, bboxes,
566                                     dimensions, null, authorityURLs, identifiers, metadataURLs, dataURLs, featureListURLs,
567                                     styles, null, null, parent );
568    
569            // get Child layers
570            nl = XMLTools.getElements( layerElem, PWMS + "Layer", nsContext );
571            Layer[] layers = new Layer[nl.size()];
572            for ( int i = 0; i < layers.length; i++ ) {
573                layers[i] = parseLayers( nl.get( i ), layer, scaleHint );
574            }
575    
576            // set child layers
577            layer.setLayer( layers );
578    
579            return layer;
580        }
581    
582        /*
583         * Prefix added. Changed to Min/MaxScaleDenominator.
584         */
585        @Override
586        protected ScaleHint parseScaleHint( Element layerElem, ScaleHint scaleHint )
587                                throws XMLParsingException {
588    
589            Node min = XMLTools.getNode( layerElem, PWMS + "MinScaleDenominator", nsContext );
590            Node max = XMLTools.getNode( layerElem, PWMS + "MaxScaleDenominator", nsContext );
591            if ( min != null ) {
592                double mn = XMLTools.getRequiredNodeAsDouble( min, ".", nsContext );
593                double mx = XMLTools.getRequiredNodeAsDouble( max, ".", nsContext );
594                scaleHint = new ScaleHint( mn, mx );
595            }
596    
597            if ( scaleHint == null ) {
598                scaleHint = new ScaleHint( 0, Double.MAX_VALUE );
599            }
600    
601            return scaleHint;
602        }
603    
604        /*
605         * Prefix added. The following attributes have to be implemented: TODO
606         */
607        // <attribute name="name" type="string" use="required"/>
608        // <attribute name="units" type="string" use="required"/>
609        // <attribute name="unitSymbol" type="string"/>
610        // <attribute name="default" type="string"/>
611        // <attribute name="multipleValues" type="boolean"/>
612        // <attribute name="nearestValue" type="boolean"/>
613        // <attribute name="current" type="boolean"/>
614        @Override
615        protected Dimension[] parseDimensions( Element layerElem )
616                                throws XMLParsingException {
617    
618            List<?> nl = XMLTools.getNodes( layerElem, PWMS + "Dimension", nsContext );
619            Dimension[] dimensions = new Dimension[nl.size()];
620            for ( int i = 0; i < dimensions.length; i++ ) {
621                String name = XMLTools.getNodeAsString( (Node) nl.get( i ), "./@name", nsContext, null );
622                String units = XMLTools.getNodeAsString( (Node) nl.get( i ), "./@units", nsContext, null );
623                String unitSymbol = XMLTools.getNodeAsString( (Node) nl.get( i ), "./@unitSymbol", nsContext, null );
624                dimensions[i] = new Dimension( name, units, unitSymbol );
625            }
626    
627            return dimensions;
628        }
629    
630        /*
631         * Prefix added.
632         */
633        @Override
634        protected Attribution parseAttribution( Element layerElem )
635                                throws XMLParsingException {
636    
637            Attribution attribution = null;
638            Node node = XMLTools.getNode( layerElem, PWMS + "Attribution", nsContext );
639            if ( node != null ) {
640                String title = XMLTools.getRequiredNodeAsString( layerElem, PWMS + "Attribution/" + PWMS + "Title",
641                                                                 nsContext );
642                OnlineResource onLineResource = parseOnLineResource( (Element) XMLTools.getRequiredNode(
643                                                                                                         node,
644                                                                                                         PWMS
645                                                                                                                                 + "OnlineResource",
646                                                                                                         nsContext ) );
647                node = XMLTools.getNode( node, PWMS + "LogoURL", nsContext );
648                LogoURL logoURL = null;
649                if ( node != null ) {
650                    int width = XMLTools.getRequiredNodeAsInt( node, "./@width", nsContext );
651                    int height = XMLTools.getRequiredNodeAsInt( node, "./@height", nsContext );
652                    String format = XMLTools.getRequiredNodeAsString( node, "./Format", nsContext );
653                    OnlineResource logoOR = parseOnLineResource( (Element) XMLTools.getRequiredNode(
654                                                                                                     node,
655                                                                                                     PWMS
656                                                                                                                             + "OnlineResource",
657                                                                                                     nsContext ) );
658                    logoURL = new LogoURL( width, height, format, logoOR.getLinkage().getHref() );
659                }
660                attribution = new Attribution( title, onLineResource.getLinkage().getHref(), logoURL );
661            }
662    
663            return attribution;
664        }
665    
666        /*
667         * Prefix added.
668         */
669        @Override
670        protected AuthorityURL[] parseAuthorityURLs( Element layerElem )
671                                throws XMLParsingException {
672    
673            List<?> nl = XMLTools.getNodes( layerElem, PWMS + "AuthorityURL", nsContext );
674            AuthorityURL[] authorityURLs = new AuthorityURL[nl.size()];
675            for ( int i = 0; i < authorityURLs.length; i++ ) {
676                String name = XMLTools.getRequiredNodeAsString( (Node) nl.get( i ), "./@name", nsContext );
677                Element tmp = (Element) XMLTools.getRequiredNode( (Node) nl.get( i ), PWMS + "OnlineResource", nsContext );
678                OnlineResource olr = parseOnLineResource( tmp );
679                authorityURLs[i] = new AuthorityURL( name, olr.getLinkage().getHref() );
680            }
681    
682            return authorityURLs;
683        }
684    
685        /*
686         * Prefix added.
687         */
688        @Override
689        protected MetadataURL[] parseMetadataURLs( Element layerElem )
690                                throws XMLParsingException {
691    
692            List<?> nl = XMLTools.getNodes( layerElem, PWMS + "MetadataURL", nsContext );
693            MetadataURL[] metadataURL = new MetadataURL[nl.size()];
694            for ( int i = 0; i < metadataURL.length; i++ ) {
695                String type = XMLTools.getRequiredNodeAsString( (Node) nl.get( i ), "./@type", nsContext );
696                String format = XMLTools.getRequiredNodeAsString( (Node) nl.get( i ), PWMS + "Format", nsContext );
697                Element tmp = (Element) XMLTools.getRequiredNode( (Node) nl.get( i ), PWMS + "OnlineResource", nsContext );
698                OnlineResource olr = parseOnLineResource( tmp );
699                metadataURL[i] = new MetadataURL( type, format, olr.getLinkage().getHref() );
700    
701            }
702    
703            return metadataURL;
704        }
705    
706        /*
707         * Prefix added.
708         */
709        @Override
710        protected DataURL[] parseDataURL( Element layerElem )
711                                throws XMLParsingException {
712    
713            List<?> nl = XMLTools.getNodes( layerElem, PWMS + "DataURL", nsContext );
714            DataURL[] dataURL = new DataURL[nl.size()];
715            for ( int i = 0; i < dataURL.length; i++ ) {
716    
717                String format = XMLTools.getRequiredNodeAsString( (Node) nl.get( i ), PWMS + "Format", nsContext );
718                Element tmp = (Element) XMLTools.getRequiredNode( (Node) nl.get( i ), PWMS + "OnlineResource", nsContext );
719                OnlineResource olr = parseOnLineResource( tmp );
720                dataURL[i] = new DataURL( format, olr.getLinkage().getHref() );
721    
722            }
723    
724            return dataURL;
725        }
726    
727        /*
728         * Prefix added.
729         */
730        @Override
731        protected FeatureListURL[] parseFeatureListURL( Element layerElem )
732                                throws XMLParsingException {
733    
734            List<?> nl = XMLTools.getNodes( layerElem, PWMS + "FeatureListURL", nsContext );
735            FeatureListURL[] flURL = new FeatureListURL[nl.size()];
736            for ( int i = 0; i < flURL.length; i++ ) {
737    
738                String format = XMLTools.getRequiredNodeAsString( (Node) nl.get( i ), "./Format", nsContext );
739                Element tmp = (Element) XMLTools.getRequiredNode( (Node) nl.get( i ), PWMS + "OnlineResource", nsContext );
740                OnlineResource olr = parseOnLineResource( tmp );
741                flURL[i] = new FeatureListURL( format, olr.getLinkage().getHref() );
742    
743            }
744    
745            return flURL;
746        }
747    
748        /*
749         * Prefix added.
750         */
751        @Override
752        protected Style[] parseStyles( Element layerElem )
753                                throws XMLParsingException {
754    
755            List<?> nl = XMLTools.getNodes( layerElem, PWMS + "Style", nsContext );
756            Style[] styles = new Style[nl.size()];
757            for ( int i = 0; i < styles.length; i++ ) {
758                String name = XMLTools.getRequiredNodeAsString( (Node) nl.get( i ), PWMS + "Name", nsContext );
759    
760                if ( name == null ) {
761                    throw new XMLParsingException( Messages.getMessage( "WMS_STYLENAME" ) );
762                }
763                String title = XMLTools.getNodeAsString( (Node) nl.get( i ), PWMS + "Title", nsContext, null );
764                if ( title == null ) {
765                    throw new XMLParsingException( Messages.getMessage( "WMS_STYLETITLE" ) );
766                }
767                String styleAbstract = XMLTools.getNodeAsString( (Node) nl.get( i ), PWMS + "Abstract", nsContext, null );
768                LegendURL[] legendURLs = parseLegendURL( (Node) nl.get( i ) );
769                StyleURL styleURL = parseStyleURL( (Node) nl.get( i ) );
770                StyleSheetURL styleSheetURL = parseStyleSheetURL( (Node) nl.get( i ) );
771    
772                styles[i] = new Style( name, title, styleAbstract, legendURLs, styleSheetURL, styleURL, null );
773            }
774    
775            return styles;
776        }
777    
778        /*
779         * Prefix added.
780         */
781        @Override
782        protected LegendURL[] parseLegendURL( Node node )
783                                throws XMLParsingException {
784    
785            List<?> nl = XMLTools.getNodes( node, PWMS + "LegendURL", nsContext );
786            LegendURL[] lURL = new LegendURL[nl.size()];
787            for ( int i = 0; i < lURL.length; i++ ) {
788                int width = XMLTools.getRequiredNodeAsInt( (Node) nl.get( i ), "./@width", nsContext );
789                int height = XMLTools.getRequiredNodeAsInt( (Node) nl.get( i ), "./@height", nsContext );
790                String format = XMLTools.getRequiredNodeAsString( (Node) nl.get( i ), PWMS + "Format", nsContext );
791                Element tmp = (Element) XMLTools.getRequiredNode( (Node) nl.get( i ), PWMS + "OnlineResource", nsContext );
792                OnlineResource olr = parseOnLineResource( tmp );
793                lURL[i] = new LegendURL( width, height, format, olr.getLinkage().getHref() );
794    
795            }
796    
797            return lURL;
798        }
799    
800        /*
801         * Prefix added.
802         */
803        @Override
804        protected StyleURL parseStyleURL( Node node )
805                                throws XMLParsingException {
806    
807            StyleURL styleURL = null;
808            Node styleNode = XMLTools.getNode( node, PWMS + "StyleURL", nsContext );
809    
810            if ( styleNode != null ) {
811                String format = XMLTools.getRequiredNodeAsString( styleNode, PWMS + "Format", nsContext );
812                Element tmp = (Element) XMLTools.getRequiredNode( styleNode, PWMS + "OnlineResource", nsContext );
813                OnlineResource olr = parseOnLineResource( tmp );
814                styleURL = new StyleURL( format, olr.getLinkage().getHref() );
815    
816            }
817    
818            return styleURL;
819        }
820    
821        /*
822         * Prefix added.
823         */
824        @Override
825        protected StyleSheetURL parseStyleSheetURL( Node node )
826                                throws XMLParsingException {
827    
828            StyleSheetURL styleSheetURL = null;
829            Node styleNode = XMLTools.getNode( node, PWMS + "StyleSheetURL", nsContext );
830    
831            if ( styleNode != null ) {
832                String format = XMLTools.getRequiredNodeAsString( styleNode, PWMS + "Format", nsContext );
833                Element tmp = (Element) XMLTools.getRequiredNode( styleNode, PWMS + "OnlineResource", nsContext );
834                OnlineResource olr = parseOnLineResource( tmp );
835                styleSheetURL = new StyleSheetURL( format, olr.getLinkage().getHref() );
836    
837            }
838    
839            return styleSheetURL;
840        }
841    
842        /*
843         * Prefix added.
844         */
845        @Override
846        protected Identifier[] parseIdentifiers( Element layerElem )
847                                throws XMLParsingException {
848    
849            List<?> nl = XMLTools.getNodes( layerElem, PWMS + "Identifier", nsContext );
850            Identifier[] identifiers = new Identifier[nl.size()];
851            for ( int i = 0; i < identifiers.length; i++ ) {
852                String value = XMLTools.getStringValue( (Node) nl.get( i ) );
853                String authority = XMLTools.getNodeAsString( layerElem, "./@authority", nsContext, null );
854                identifiers[i] = new Identifier( value, authority );
855            }
856    
857            return identifiers;
858        }
859    
860        /*
861         * Changed SRS to CRS.
862         */
863        @Override
864        protected LayerBoundingBox[] parseLayerBoundingBoxes( List<Element> nl )
865                                throws XMLParsingException {
866            LayerBoundingBox[] llBoxes = new LayerBoundingBox[nl.size()];
867            for ( int i = 0; i < llBoxes.length; i++ ) {
868                double minx = XMLTools.getRequiredNodeAsDouble( nl.get( i ), "./@minx", nsContext );
869                double maxx = XMLTools.getRequiredNodeAsDouble( nl.get( i ), "./@maxx", nsContext );
870                double miny = XMLTools.getRequiredNodeAsDouble( nl.get( i ), "./@miny", nsContext );
871                double maxy = XMLTools.getRequiredNodeAsDouble( nl.get( i ), "./@maxy", nsContext );
872                double resx = XMLTools.getNodeAsDouble( nl.get( i ), "./@resx", nsContext, -1 );
873                double resy = XMLTools.getNodeAsDouble( nl.get( i ), "./@resx", nsContext, -1 );
874                String srs = XMLTools.getRequiredNodeAsString( nl.get( i ), "./@CRS", nsContext );
875                if ( srs.startsWith( "EPSG" ) ) {
876                    Position min = GeometryFactory.createPosition( miny, minx );
877                    Position max = GeometryFactory.createPosition( maxy, maxx );
878                    llBoxes[i] = new LayerBoundingBox( min, max, srs, resx, resy );
879                } else {
880                    Position min = GeometryFactory.createPosition( minx, miny );
881                    Position max = GeometryFactory.createPosition( maxx, maxy );
882                    llBoxes[i] = new LayerBoundingBox( min, max, srs, resx, resy );
883                }
884            }
885    
886            return llBoxes;
887        }
888    
889        /**
890         * 
891         * @param llBox
892         * @return the envelope
893         * @throws XMLParsingException
894         * @throws UnknownCRSException
895         */
896        protected Envelope parseEX_GeographicBoundingBox( Element llBox )
897                                throws XMLParsingException, UnknownCRSException {
898    
899            double minx = XMLTools.getRequiredNodeAsDouble( llBox, PWMS + "westBoundLongitude", nsContext );
900            double maxx = XMLTools.getRequiredNodeAsDouble( llBox, PWMS + "eastBoundLongitude", nsContext );
901            double miny = XMLTools.getRequiredNodeAsDouble( llBox, PWMS + "southBoundLatitude", nsContext );
902            double maxy = XMLTools.getRequiredNodeAsDouble( llBox, PWMS + "northBoundLatitude", nsContext );
903            CoordinateSystem crs = CRSFactory.create( "EPSG:4326" );
904    
905            Envelope env = GeometryFactory.createEnvelope( minx, miny, maxx, maxy, crs );
906    
907            return env;
908        }
909    
910    }