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