001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_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 }