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