001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/ogcwebservices/wms/capabilities/Layer.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2006 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/deegree/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     This library is free software; you can redistribute it and/or
012     modify it under the terms of the GNU Lesser General Public
013     License as published by the Free Software Foundation; either
014     version 2.1 of the License, or (at your option) any later version.
015    
016     This library is distributed in the hope that it will be useful,
017     but WITHOUT ANY WARRANTY; without even the implied warranty of
018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019     Lesser General Public License for more details.
020    
021     You should have received a copy of the GNU Lesser General Public
022     License along with this library; if not, write to the Free Software
023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024    
025     Contact:
026    
027     Andreas Poth
028     lat/lon GmbH
029     Aennchenstr. 19
030     53115 Bonn
031     Germany
032     E-Mail: poth@lat-lon.de
033    
034     Prof. Dr. Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: greve@giub.uni-bonn.de
041    
042     
043     ---------------------------------------------------------------------------*/
044    package org.deegree.ogcwebservices.wms.capabilities;
045    
046    import java.util.ArrayList;
047    import java.util.Arrays;
048    import java.util.HashMap;
049    import java.util.List;
050    
051    import org.deegree.graphics.sld.UserStyle;
052    import org.deegree.model.spatialschema.Envelope;
053    import org.deegree.ogcwebservices.getcapabilities.MetadataURL;
054    import org.deegree.ogcwebservices.wms.configuration.AbstractDataSource;
055    
056    /**
057     * Each available map is advertised by a <Layer> element in the Capabilities XML. A single
058     * parent Layer encloses any number of additional layers, which may be hierarchically nested as
059     * desired. Some properties defined in a parent layer are inherited by the children it encloses.
060     * These inherited properties may be either redefined or added to by the child.
061     * <p>
062     * A Map Server shall include at least one &lt;Layer&gt; element for each map layer offered. If
063     * desired, layers may be repeated in different categories when relevant. No controlled vocabulary
064     * has been defined, so at present Layer and Style Names, Titles and Keywords are arbitrary.
065     * </p>
066     * The &lt;Layer&gt; element can enclose child elements providing metadata about the Layer.
067     * 
068     * @author <a href="mailto:k.lupp@web.de">Katharina Lupp </a>
069     * @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider </a>
070     * @author last edited by: $Author: aschmitz $
071     * @version 2002-03-01
072     */
073    public class Layer {
074    
075        private List<AuthorityURL> authorityURL;
076    
077        private List<Envelope> boundingBox;
078    
079        private List<AbstractDataSource> dataSource;
080    
081        private List<DataURL> dataURL;
082    
083        private List<Dimension> dimension;
084    
085        private List<Extent> extent;
086    
087        private List<FeatureListURL> featureListURL;
088    
089        private List<Identifier> identifier;
090    
091        private List<String> keywordList;
092    
093        private List<Layer> layer;
094    
095        private List<MetadataURL> metadataURL;
096    
097        private List<String> srs;
098    
099        private Attribution attribution;
100    
101        private Envelope latLonBoundingBox;
102    
103        private HashMap<String, Style> styles;
104    
105        private Layer parent;
106    
107        private ScaleHint scaleHint;
108    
109        private String abstract_;
110    
111        private String name;
112    
113        private String title;
114    
115        private boolean noSubsets = false;
116    
117        private boolean opaque = false;
118    
119        private boolean queryable = false;
120    
121        private int cascaded = -1;
122    
123        private int fixedHeight = -1;
124    
125        private int fixedWidth = -1;
126    
127        /**
128         * default constructor
129         */
130        private Layer() {
131            keywordList = new ArrayList<String>( 20 );
132            srs = new ArrayList<String>( 20 );
133            boundingBox = new ArrayList<Envelope>();
134            dimension = new ArrayList<Dimension>();
135            extent = new ArrayList<Extent>();
136            authorityURL = new ArrayList<AuthorityURL>();
137            identifier = new ArrayList<Identifier>();
138            metadataURL = new ArrayList<MetadataURL>();
139            dataURL = new ArrayList<DataURL>();
140            featureListURL = new ArrayList<FeatureListURL>();
141            styles = new HashMap<String, Style>();
142            layer = new ArrayList<Layer>( 50 );
143            dataSource = new ArrayList<AbstractDataSource>();
144        }
145    
146        /**
147         * constructor initializing the class with the &lt;Layer&gt;
148         * 
149         * @param queryable
150         * @param cascaded
151         * @param opaque
152         * @param noSubsets
153         * @param fixedWidth
154         * @param fixedHeight
155         * @param name
156         * @param title
157         * @param abstract_
158         * @param latLonBoundingBox
159         * @param attribution
160         * @param scaleHint
161         * @param keywordList
162         * @param srs
163         * @param boundingBoxes
164         * @param dimensions
165         * @param extents
166         * @param authorityURLs
167         * @param identifiers
168         * @param metadataURLs
169         * @param dataURLs
170         * @param featureListURLs
171         * @param styles
172         * @param layers
173         * @param dataSource
174         * @param parent
175         */
176        public Layer( boolean queryable, int cascaded, boolean opaque, boolean noSubsets,
177                      int fixedWidth, int fixedHeight, String name, String title, String abstract_,
178                      Envelope latLonBoundingBox, Attribution attribution, ScaleHint scaleHint,
179                      String[] keywordList, String[] srs, LayerBoundingBox[] boundingBoxes,
180                      Dimension[] dimensions, Extent[] extents, AuthorityURL[] authorityURLs,
181                      Identifier[] identifiers, MetadataURL[] metadataURLs, DataURL[] dataURLs,
182                      FeatureListURL[] featureListURLs, Style[] styles, Layer[] layers,
183                      AbstractDataSource[] dataSource, Layer parent ) {
184            this();
185            this.queryable = queryable;
186            this.cascaded = cascaded;
187            this.opaque = opaque;
188            this.noSubsets = noSubsets;
189            this.fixedWidth = fixedWidth;
190            this.fixedHeight = fixedHeight;
191            setName( name );
192            setTitle( title );
193            setAbstract( abstract_ );
194            setLatLonBoundingBox( latLonBoundingBox );
195            setAttribution( attribution );
196            setScaleHint( scaleHint );
197            setKeywordList( keywordList );
198            setSrs( srs );
199            setBoundingBox( boundingBoxes );
200            setDimension( dimensions );
201            setExtent( extents );
202            setAuthorityURL( authorityURLs );
203            setIdentifier( identifiers );
204            setMetadataURL( metadataURLs );
205            setDataURL( dataURLs );
206            setFeatureListURL( featureListURLs );
207            setStyles( styles );
208            setLayer( layers );
209            setDataSource( dataSource );
210            setParent( parent );
211        }
212    
213        /**
214         * If, and only if, a layer has a &lt;Name&gt;, then it is a map layer that can be requested by
215         * using that Name in the LAYERS parameter of a GetMap request. If the layer has a Title but no
216         * Name, then that layer is only a category title for all the layers nested within. A Map Server
217         * that advertises a Layer containing a Name element shall be able to accept that Name as the
218         * value of LAYERS argument in a GetMap request and return the corresponding map. A Client shall
219         * not attempt to request a layer that has a Title but no Name.
220         * 
221         * @return the name
222         */
223        public String getName() {
224            return name;
225        }
226    
227        /**
228         * sets the name of the layer
229         * 
230         * @param name
231         */
232        public void setName( String name ) {
233            this.name = name;
234        }
235    
236        /**
237         * A &lt;Title&gt; is required for all layers; it is a human-readable string for presentation in
238         * a menu. The Title is not inherited by child Layers.
239         * 
240         * @return the title
241         */
242        public String getTitle() {
243            return title;
244        }
245    
246        /**
247         * sets the title for the layer
248         * 
249         * @param title
250         */
251        public void setTitle( String title ) {
252            this.title = title;
253        }
254    
255        /**
256         * Abstract is a narrative description of the map layer. The Abstract elements are not inherited
257         * by child Layers.
258         * 
259         * @return the abstract
260         */
261        public String getAbstract() {
262            return abstract_;
263        }
264    
265        /**
266         * sets the a narrative description of the map layer
267         * 
268         * @param abstract_
269         */
270        public void setAbstract( String abstract_ ) {
271            this.abstract_ = abstract_;
272        }
273    
274        /**
275         * KeywordList contains zero or more Keywords to aid in catalog searches. The KeywordList
276         * elements are not inherited by child Layers.
277         * 
278         * @return the keywords
279         */
280        public String[] getKeywordList() {
281            return keywordList.toArray( new String[keywordList.size()] );
282        }
283    
284        /**
285         * adds the keywordList
286         * 
287         * @param keyword
288         */
289        public void addKeyword( String keyword ) {
290            this.keywordList.add( keyword );
291        }
292    
293        /**
294         * sets the keywordList
295         * 
296         * @param keywordList
297         */
298        public void setKeywordList( String[] keywordList ) {
299            if ( keywordList == null )
300                this.keywordList.clear();
301            else
302                this.keywordList = Arrays.asList( keywordList );
303        }
304    
305        /**
306         * Every Layer is available in one or more spatial reference systems Every Layer shall have at
307         * least one &gt;SRS&gt; element that is either stated explicitly or inherited from a parent
308         * Layer . The root &lt;Layer&gt; element shall include a sequence of zero or more SRS elements
309         * listing all SRSes that are common to all subsidiary layers. Use a single SRS element with
310         * empty content (like so: "&lt;SRS&gt;&lt;/SRS&gt; ") if there is no common SRS. Layers may
311         * optionally add to the global SRS list, or to the list inherited from a parent layer. Any
312         * duplication shall be ignored by clients. When a Layer is available in several Spatial
313         * Reference Systems, there are two ways to encode the list of SRS values. The first of these is
314         * new in this version of the specification, the second is deprecated but still included for
315         * backwards compatibility.
316         * <p>
317         * 1. Optional, recommended: Multiple single-valued &lt;SRS&gt; elements: a list of SRS values
318         * is represented as a sequence of &lt;SRS&gt; elements, each of which contains only a single
319         * SRS name. Example: &lt;SRS&gt;EPSG:1234&lt;/SRS&gt; &lt;SRS&gt;EPSG:5678&lt;/SRS&gt;.
320         * </p>
321         * 2. Deprecated: Single list-valued &lt;SRS&gt; element: a list of SRS values is represented
322         * asa whitespace-separated list of SRS names contained within a single &lt;SRS&gt; element.
323         * Example: &lt;SRS&gt;EPSG:1234 EPSG:5678&lt;/SRS&gt;.
324         * 
325         * @return the srs
326         */
327        public String[] getSrs() {
328            String[] pSrs = null;
329    
330            if ( parent != null ) {
331                pSrs = parent.getSrs();
332            } else {
333                pSrs = new String[0];
334            }
335    
336            List<String> list = new ArrayList<String>( srs.size() + pSrs.length );
337            list.addAll( srs );
338            for ( int i = 0; i < pSrs.length; i++ ) {
339                if ( !list.contains( pSrs[i] ) ) {
340                    list.add( pSrs[i] );
341                }
342            }
343    
344            return list.toArray( new String[list.size()] );
345        }
346    
347        /**
348         * @param srs
349         * @return s true if the submitted srs (name) is supported by the layer
350         */
351        public boolean isSrsSupported( String srs ) {
352            String[] sr = getSrs();
353            for ( int i = 0; i < sr.length; i++ ) {
354                if ( sr[i].equals( srs ) ) {
355                    return true;
356                }
357            }
358            return false;
359        }
360    
361        /**
362         * adds the spatial reference system (srs)
363         * 
364         * @param srs
365         */
366        public void addSrs( String srs ) {
367            this.srs.add( srs );
368        }
369    
370        /**
371         * sets the srs
372         * 
373         * @param srs
374         */
375        public void setSrs( String[] srs ) {
376            if ( srs == null )
377                this.srs.clear();
378            else
379                this.srs = Arrays.asList( srs );
380        }
381    
382        /**
383         * Every Layer shall have exactly one &lt;LatLonBoundingBox&gt; element that is either stated
384         * explicitly or inherited from a parent Layer. LatLonBoundingBox states the minimum bounding
385         * rectangle of the map data in the EPSG:4326 geographic coordinate system. The
386         * LatLonBoundingBox attributes minx, miny, maxx, maxy indicate the edges of an enclosing
387         * rectangle in decimal degrees. LatLonBoundingBox shall be supplied regardless of what SRS the
388         * map server may support, but it may be approximate if EPSG:4326 is not supported. Its purpose
389         * is to facilitate geographic searches without requiring coordinate transformations by the
390         * search engine.
391         * 
392         * @return the bbox
393         */
394        public Envelope getLatLonBoundingBox() {
395            if ( ( latLonBoundingBox == null ) && ( parent != null ) ) {
396                return parent.getLatLonBoundingBox();
397            }
398            return latLonBoundingBox;
399        }
400    
401        /**
402         * sets the LatLonBoundingBox element that is either stated explicitly or inherited from a
403         * parent Layer.
404         * 
405         * @param latLonBoundingBox
406         */
407        public void setLatLonBoundingBox( Envelope latLonBoundingBox ) {
408            this.latLonBoundingBox = latLonBoundingBox;
409        }
410    
411        /**
412         * Layers may have zero or more &lt;BoundingBox&gt; elements that are either stated explicitly
413         * or inherited from a parent Layer. Each BoundingBox states the bounding rectangle of the map
414         * data in a particular spatial reference system; the attribute SRS indicates which SRS applies.
415         * If the data area is shaped irregularly then the BoundingBox gives the minimum enclosing
416         * rectangle. The attributes minx, miny, maxx, maxy indicate the edges of the bounding box in
417         * units of the specified SRS. Optional resx and resy attributes indicate the spatial resolution
418         * of the data in those same units.
419         * <p>
420         * A Layer may have multiple BoundingBox element, but each one shall state a different SRS. A
421         * Layer inherits any BoundingBox values defined by its parents. A BoundingBox inherited from
422         * the parent Layer for a particular SRS is replaced by any declaration for the same SRS in the
423         * child Layer. A BoundingBox in the child for a new SRS not already declared by the parent is
424         * added to the list of bounding boxes for the child Layer. A single Layer element shall not
425         * contain more than one BoundingBox for the same SRS.
426         * </p>
427         * 
428         * @return bounding boxes
429         */
430        public LayerBoundingBox[] getBoundingBoxes() {
431            HashMap<String, LayerBoundingBox> list = new HashMap<String, LayerBoundingBox>( 100 );
432    
433            if ( parent != null ) {
434                LayerBoundingBox[] plb = parent.getBoundingBoxes();
435    
436                for ( int i = 0; i < plb.length; i++ ) {
437                    list.put( plb[i].getSRS(), plb[i] );
438                }
439            }
440    
441            for ( int i = 0; i < boundingBox.size(); i++ ) {
442                LayerBoundingBox lb = (LayerBoundingBox) boundingBox.get( i );
443                list.put( lb.getSRS(), lb );
444            }
445    
446            LayerBoundingBox[] lbs = new LayerBoundingBox[list.size()];
447            return list.values().toArray( lbs );
448        }
449    
450        /**
451         * adds the &lt;BoundingBox&gt;
452         * 
453         * @param boundingBox
454         */
455        public void addBoundingBox( Envelope boundingBox ) {
456            this.boundingBox.add( boundingBox );
457        }
458    
459        /**
460         * sets the boundingBox
461         * 
462         * @param boundingBox
463         */
464        public void setBoundingBox( LayerBoundingBox[] boundingBox ) {
465            this.boundingBox.clear();
466    
467            if ( boundingBox != null ) {
468                for ( int i = 0; i < boundingBox.length; i++ ) {
469                    this.boundingBox.add( boundingBox[i] );
470                }
471            }
472        }
473    
474        /**
475         * Dimension declarations are inherited from parent Layers. Any new Dimension declarations in
476         * the child are added to the list inherited from the parent. A child shall not redefine a
477         * Dimension with the same name attribute as one that was inherited.
478         * 
479         * @return the dimensions
480         */
481        public Dimension[] getDimension() {
482            HashMap<String, Dimension> list = new HashMap<String, Dimension>();
483    
484            if ( parent != null ) {
485                Dimension[] pDim = parent.getDimension();
486    
487                for ( int i = 0; i < pDim.length; i++ ) {
488                    list.put( pDim[i].getName(), pDim[i] );
489                }
490            }
491    
492            for ( int i = 0; i < dimension.size(); i++ ) {
493                Dimension dim = dimension.get( i );
494    
495                if ( list.get( dim.getName() ) == null ) {
496                    list.put( dim.getName(), dim );
497                }
498            }
499    
500            return list.values().toArray( new Dimension[list.size()] );
501        }
502    
503        /**
504         * adds the dimension
505         * 
506         * @param dimension
507         */
508        public void addDimension( Dimension dimension ) {
509            this.dimension.add( dimension );
510        }
511    
512        /**
513         * sets the dimension
514         * 
515         * @param dimension
516         */
517        public void setDimension( Dimension[] dimension ) {
518            if ( dimension == null )
519                this.dimension.clear();
520            else
521                this.dimension = Arrays.asList( dimension );
522        }
523    
524        /**
525         * Extent declarations are inherited from parent Layers. Any Extent declarations in the child
526         * with the same name attribute as one inherited from the parent replaces the value declared by
527         * the parent. A Layer shall not declare an Extent unless a Dimension with the same name has
528         * been declared or inherited earlier in the Capabilities XML.
529         * 
530         * @return the extents
531         */
532        public Extent[] getExtent() {
533            HashMap<String, Extent> list = new HashMap<String, Extent>();
534    
535            if ( parent != null ) {
536                Extent[] pEx = parent.getExtent();
537    
538                for ( int i = 0; i < pEx.length; i++ ) {
539                    list.put( pEx[i].getName(), pEx[i] );
540                }
541            }
542    
543            for ( int i = 0; i < extent.size(); i++ ) {
544                Extent ex = extent.get( i );
545                list.put( ex.getName(), ex );
546            }
547    
548            return list.values().toArray( new Extent[list.size()] );
549        }
550    
551        /**
552         * adds the extent declarations
553         * 
554         * @param extent
555         */
556        public void addExtent( Extent extent ) {
557            this.extent.add( extent );
558        }
559    
560        /**
561         * sets the extent
562         * 
563         * @param extent
564         */
565        public void setExtent( Extent[] extent ) {
566            if ( extent == null )
567                this.extent.clear();
568            else
569                this.extent = Arrays.asList( extent );
570        }
571    
572        /**
573         * The optional &lt;Attribution&gt; element provides a way to identify the source of the map
574         * data used in a Layer or collection of Layers. Attribution encloses several optional elements:
575         * <OnlineResource>states the data provider's URL; &lt;Title&gt; is a human-readable string
576         * naming the data provider; &lt;LogoURL&gt; is the URL of a logo image. Client applications may
577         * choose to display one or more of these items. A &lt;Format&gt; element in LogoURL indicates
578         * the MIME type of the logo image, and the attributes width and height state the size of the
579         * image in pixels.
580         * 
581         * @return the attribution
582         */
583        public Attribution getAttribution() {
584            if ( ( parent != null ) && ( attribution == null ) ) {
585                return parent.getAttribution();
586            }
587            return attribution;
588        }
589    
590        /**
591         * sets the optional &lt;Attribution&gt; element
592         * 
593         * @param attribution
594         */
595        public void setAttribution( Attribution attribution ) {
596            this.attribution = attribution;
597        }
598    
599        /**
600         * The authority attribute of the Identifier element corresponds to the name attribute of a
601         * separate &lt;AuthorityURL&gt; element. AuthorityURL encloses an &lt;OnlineResource&gt;
602         * element which states the URL of a document defining the meaning of the Identifier values.
603         * 
604         * @return the authority url object
605         */
606        public AuthorityURL[] getAuthorityURL() {
607            HashMap<String, AuthorityURL> list = new HashMap<String, AuthorityURL>();
608    
609            if ( parent != null ) {
610                AuthorityURL[] pAu = parent.getAuthorityURL();
611    
612                for ( int i = 0; i < pAu.length; i++ ) {
613                    list.put( pAu[i].getName(), pAu[i] );
614                }
615            }
616    
617            for ( int i = 0; i < authorityURL.size(); i++ ) {
618                AuthorityURL au = authorityURL.get( i );
619    
620                if ( list.get( au.getName() ) == null ) {
621                    list.put( au.getName(), au );
622                }
623            }
624    
625            AuthorityURL[] aus = new AuthorityURL[list.size()];
626            return list.values().toArray( aus );
627        }
628    
629        /**
630         * adds the authority attribute of the Identifier element
631         * 
632         * @param authorityURL
633         */
634        public void addAuthorityURL( AuthorityURL authorityURL ) {
635            this.authorityURL.add( authorityURL );
636        }
637    
638        /**
639         * sets the authority attribute of the Identifier element
640         * 
641         * @param authorityURL
642         */
643        public void setAuthorityURL( AuthorityURL[] authorityURL ) {
644            if ( authorityURL == null )
645                this.authorityURL.clear();
646            else
647                this.authorityURL = Arrays.asList( authorityURL );
648        }
649    
650        /**
651         * A Map Server may use zero or more &lt;Identifier&gt; elements to list ID numbers or labels
652         * defined by a particular Authority. The text content of the Identifier element is the ID
653         * value.
654         * 
655         * @return the identifiers
656         */
657        public Identifier[] getIdentifier() {
658            HashMap<String, Identifier> list = new HashMap<String, Identifier>();
659    
660            if ( parent != null ) {
661                Identifier[] pIden = parent.getIdentifier();
662    
663                for ( int i = 0; i < pIden.length; i++ ) {
664                    list.put( pIden[i].getAuthority(), pIden[i] );
665                }
666            }
667    
668            for ( int i = 0; i < identifier.size(); i++ ) {
669                Identifier iden = identifier.get( i );
670    
671                if ( list.get( iden.getAuthority() ) == null ) {
672                    list.put( iden.getAuthority(), iden );
673                }
674            }
675    
676            Identifier[] ids = new Identifier[list.size()];
677            return list.values().toArray( ids );
678        }
679    
680        /**
681         * adds the &lt;Identifier&gt;
682         * 
683         * @param identifier
684         */
685        public void addIdentifier( Identifier identifier ) {
686            this.identifier.add( identifier );
687        }
688    
689        /**
690         * sets the &lt;Identifier&gt;
691         * 
692         * @param identifier
693         */
694        public void setIdentifier( Identifier[] identifier ) {
695            if ( identifier == null )
696                this.identifier.clear();
697            else
698                this.identifier = Arrays.asList( identifier );
699        }
700    
701        /**
702         * A Map Server should use one or more &lt;MetadataURL&gt; elements to offer detailed,
703         * standardized metadata about the data underneath a particular layer. The type attribute
704         * indicates the standard to which the metadata complies. Two types are defined at present: the
705         * value 'TC211' refers to [ISO 19115]; the value 'FGDC' refers to [FGDC-STD-001-1988]. The
706         * MetadataURL element shall not be used to reference metadata in a non-standardized metadata
707         * format; see DataURL instead. The enclosed &lt;Format&gt; element indicates the file format
708         * MIME type of the metadata record.
709         * 
710         * @return the metadata urls
711         */
712        public MetadataURL[] getMetadataURL() {
713            return metadataURL.toArray( new MetadataURL[metadataURL.size()] );
714        }
715    
716        /**
717         * adds the metadataURL
718         * 
719         * @param metadataURL
720         */
721        public void addMetadataURL( MetadataURL metadataURL ) {
722            this.metadataURL.add( metadataURL );
723        }
724    
725        /**
726         * sets the metadataURL
727         * 
728         * @param metadataURL
729         */
730        public void setMetadataURL( MetadataURL[] metadataURL ) {
731            if ( metadataURL == null )
732                this.metadataURL.clear();
733            else
734                this.metadataURL = Arrays.asList( metadataURL );
735        }
736    
737        /**
738         * A Map Server may use DataURL to offer more information about the data represented by a
739         * particular layer. While the semantics are not well-defined, as long as the results of an HTTP
740         * GET request against the DataURL are properly MIME-typed, Viewer Clients and Cascading Map
741         * Servers can make use of this. Use 6lt;MetadataURL&gt; instead for a precisely defined
742         * reference to standardized metadata records.
743         * 
744         * @return the data URLs
745         */
746        public DataURL[] getDataURL() {
747            return dataURL.toArray( new DataURL[dataURL.size()] );
748        }
749    
750        /**
751         * adds the dataURL
752         * 
753         * @param dataURL
754         */
755        public void addDataURL( DataURL dataURL ) {
756            this.dataURL.add( dataURL );
757        }
758    
759        /**
760         * sets the dataURL
761         * 
762         * @param dataURL
763         */
764        public void setDataURL( DataURL[] dataURL ) {
765            if ( dataURL == null )
766                this.dataURL.clear();
767            else
768                this.dataURL = Arrays.asList( dataURL );
769        }
770    
771        /**
772         * A Map Server may use a &lt;FeatureListURL&gt; element to point to a list of the features
773         * represented in a Layer.
774         * 
775         * @return the feature list urls
776         */
777        public FeatureListURL[] getFeatureListURL() {
778            return featureListURL.toArray( new FeatureListURL[featureListURL.size()] );
779        }
780    
781        /**
782         * adds the &lt;FeatureListURL&gt;
783         * 
784         * @param featureListURL
785         */
786        public void addFeatureListURL( FeatureListURL featureListURL ) {
787            this.featureListURL.add( featureListURL );
788        }
789    
790        /**
791         * sets the &lt;FeatureListURL&gt;
792         * 
793         * @param featureListURL
794         */
795        public void setFeatureListURL( FeatureListURL[] featureListURL ) {
796            if ( featureListURL == null )
797                this.featureListURL.clear();
798            else
799                this.featureListURL = Arrays.asList( featureListURL );
800        }
801    
802        /**
803         * @return a list of style that can be used form rendering the layer.
804         */
805        public Style[] getStyles() {
806            HashMap<String, Style> list = new HashMap<String, Style>();
807    
808            if ( parent != null ) {
809                Style[] pStyle = parent.getStyles();
810    
811                for ( int i = 0; i < pStyle.length; i++ ) {
812                    list.put( pStyle[i].getName(), pStyle[i] );
813                }
814            }
815    
816            for ( Style style : styles.values() ) {
817                if ( list.get( style.getName() ) == null ) {
818                    list.put( style.getName(), style );
819                }
820            }
821    
822            return list.values().toArray( new Style[list.size()] );
823        }
824    
825        /**
826         * adds a list of style that can be used form rendering the layer.
827         * 
828         * @param style
829         */
830        public void addStyles( Style style ) {
831            this.styles.put( style.getName(), style );
832        }
833    
834        /**
835         * sets a list of style that can be used form rendering the layer.
836         * 
837         * @param styles
838         */
839        public void setStyles( Style[] styles ) {
840            if ( styles == null ) {
841                this.styles.clear();
842            } else {
843                for ( Style style : styles ) {
844                    this.styles.put( style.getName(), style );
845                }
846            }
847        }
848    
849        /**
850         * returns the <tt>UserStyle</tt> (SLD) representation of the style identified by the
851         * submitted name.
852         * 
853         * @param name
854         *            of the requested style
855         * @return SLD - UserStyle
856         * 
857         */
858        public UserStyle getStyle( String name ) {
859    
860            Style style = styles.get( name );
861            UserStyle us = null;
862    
863            if ( style == null ) {
864                if ( parent != null ) {
865                    us = parent.getStyle( name );
866                }
867            } else {
868                us = style.getStyleContent();
869            }
870    
871            return us;
872        }
873    
874        /**
875         * returns the <tt>Style</tt> identified by the submitted name.
876         * 
877         * @param name
878         *            of the requested style
879         * @return Style
880         * 
881         */
882        public Style getStyleResource( String name ) {
883    
884            Style style = styles.get( name );
885    
886            if ( style == null && name.length() == 0 ) {
887                String tmpName = "default";
888                style = styles.get( tmpName );
889                if ( style == null && name.length() == 0 ) {
890                    tmpName = "default:" + this.name;
891                    style = styles.get( tmpName );
892                }
893            } else if ( style == null && "default".equals( name ) ) {
894                String tmpName = "default:" + this.name;
895                style = styles.get( tmpName );
896            }
897    
898            if ( style == null ) {
899                if ( parent != null ) {
900                    style = parent.getStyleResource( name );
901                }
902            }
903    
904            return style;
905        }
906    
907        /**
908         * Layers may include a &lt;ScaleHint&gt; element that suggests minimum and maximum scales for
909         * which it is appropriate to display this layer. Because WMS output is destined for output
910         * devices of arbitrary size and resolution, the usual definition of scale as the ratio of map
911         * size to real-world size is not appropriate here. The following definition of Scale Hint is
912         * recommended. Consider a hypothetical map with a given Bounding Box, width and height. The
913         * central pixel of that map (or the pixel just to the northwest of center) will have some size,
914         * which can be expressed as the ground distance in meters of the southwest to northeast
915         * diagonal of that pixel. The two values in ScaleHint are the minimum and maximum recommended
916         * values of that diagonal. It is recognized that this definition is not geodetically precise,
917         * but at the same time the hope is that by including it conventions will develop that can be
918         * later specified more clearly.
919         * 
920         * @return the scale hint
921         */
922        public ScaleHint getScaleHint() {
923            if ( ( parent != null ) && ( scaleHint == null ) ) {
924                return parent.getScaleHint();
925            }
926            return scaleHint;
927        }
928    
929        /**
930         * sets the <ScaleHint>
931         * 
932         * @param scaleHint
933         */
934        public void setScaleHint( ScaleHint scaleHint ) {
935            this.scaleHint = scaleHint;
936        }
937    
938        /**
939         * returns a list of layers the are enclosed by this layer.
940         * 
941         * @return the layers
942         */
943        public Layer[] getLayer() {
944            return layer.toArray( new Layer[layer.size()] );
945        }
946    
947        /**
948         * removes a Layer identified by its name from the parent Layer. A reference to the removed
949         * layer will be returned. If no Layer matching the passed name can be found nothing happens and
950         * <tt>null</tt> will be returned.
951         * 
952         * @param name
953         * 
954         * @return removerd Layer
955         */
956        public Layer removeLayer( String name ) {
957            for ( int i = 0; i < layer.size(); i++ ) {
958                Layer ly = layer.get( i );
959                if ( ly.getName() != null ) {
960                    if ( ly.getName().equals( name ) ) {
961                        layer.remove( i );
962                        return ly;
963                    }
964                }
965            }
966            return null;
967        }
968    
969        /**
970         * removes a Layer identified by its title from the parent Layer. A reference to the removed
971         * layer will be returned. If no Layer matching the passed title can be found nothing happens
972         * and <tt>null</tt> will be returned.
973         * 
974         * @param title
975         * 
976         * @return removerd Layer
977         */
978        public Layer removeLayerByTitle( String title ) {
979            for ( int i = 0; i < layer.size(); i++ ) {
980                Layer ly = layer.get( i );
981                if ( ly.getTitle().equals( title ) ) {
982                    layer.remove( i );
983                    return ly;
984                }
985            }
986            return null;
987        }
988    
989        /**
990         * adds a list of layers the are enclosed by this layer.
991         * 
992         * @param layer
993         */
994        public void addLayer( Layer layer ) {
995            this.layer.add( layer );
996        }
997    
998        /**
999         * sets a list of layers the are enclosed by this layer.
1000         * 
1001         * @param layer
1002         */
1003        public void setLayer( Layer[] layer ) {
1004            if ( layer == null ) {
1005                this.layer.clear();
1006            } else {
1007                this.layer = new ArrayList<Layer>( Arrays.asList( layer ) );
1008            }
1009        }
1010    
1011        /**
1012         * source where the WMS can find the data of a layer.
1013         * 
1014         * @return the data sources
1015         */
1016        public AbstractDataSource[] getDataSource() {
1017            return dataSource.toArray( new AbstractDataSource[dataSource.size()] );
1018        }
1019    
1020        /**
1021         * source where the WMS can find the data of a layer.
1022         * 
1023         * @param dataSource
1024         */
1025        public void setDataSource( AbstractDataSource[] dataSource ) {
1026            if ( dataSource == null )
1027                this.dataSource.clear();
1028            else
1029                this.dataSource = Arrays.asList( dataSource );
1030        }
1031    
1032        /**
1033         * source where the WMS can find the data of a layer.
1034         * 
1035         * @param dataSource
1036         */
1037        public void addDataSource( AbstractDataSource dataSource ) {
1038            this.dataSource.add( dataSource );
1039        }
1040    
1041        /**
1042         * @return the parent layer of this layer. If the method returns <tt>null</tt> the current
1043         *         layer is the root layer. In addition with the <tt>getLayer</tt> method this enables
1044         *         a program to traverse the layer tree in both directions.
1045         */
1046        public Layer getParent() {
1047            return parent;
1048        }
1049    
1050        /**
1051         * sets the parent layer of this layer.
1052         * 
1053         * @param parent
1054         */
1055        public void setParent( Layer parent ) {
1056            this.parent = parent;
1057        }
1058    
1059        /**
1060         * @return '0' if the layer is provided directly form the deegree WMS. other it returns the
1061         *         number of cascaded WMS servers the is passed through
1062         * 
1063         */
1064        public int getCascaded() {
1065            return cascaded;
1066        }
1067    
1068        /**
1069         * @return '0' if the WMS can resize map to arbitrary height. nonzero: map has a fixed height
1070         *         that cannot be changed by the WMS.
1071         * 
1072         */
1073        public int getFixedHeight() {
1074            return fixedHeight;
1075        }
1076    
1077        /**
1078         * @return '0' if the WMS can resize map to arbitrary width. nonzero: map has a fixed width that
1079         *         cannot be changed by the WMS.
1080         * 
1081         */
1082        public int getFixedWidth() {
1083            return fixedWidth;
1084        }
1085    
1086        /**
1087         * @return false if the WMS can map a subset of the full bounding box.
1088         * 
1089         */
1090        public boolean hasNoSubsets() {
1091            return noSubsets;
1092        }
1093    
1094        /**
1095         * @return false if map data represents vector features that probably do not completely fill
1096         *         space.
1097         * 
1098         */
1099        public boolean isOpaque() {
1100            return opaque;
1101        }
1102    
1103        /**
1104         * @return true if the layer is queryable. That means it can be targeted by a GetFeatureInfo
1105         *         request.
1106         * 
1107         */
1108        public boolean isQueryable() {
1109            return queryable;
1110        }
1111    
1112    }
1113    /***************************************************************************************************
1114     * Changes to this class. What the people have been up to: $Log$ Revision 1.19 2006/09/29 15:27:43
1115     * poth bug fix - getting styles
1116     * 
1117     * Revision 1.18 2006/09/22 11:37:24 mays getStyle method enhanced
1118     * 
1119     * Revision 1.17 2006/09/18 08:33:10 poth bug fix - use List implementation that supports remove
1120     * operation for storing layers
1121     * 
1122     * Revision 1.16 2006/09/08 08:42:02 schmitz Updated the WMS to be 1.1.1 conformant once again.
1123     * Cleaned up the WMS code. Added cite WMS test data.
1124     * 
1125     * Revision 1.15 2006/08/01 19:37:49 poth comments added
1126     * 
1127     * Revision 1.14 2006/07/12 14:46:18 poth comment footer added
1128     * 
1129     **************************************************************************************************/