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