001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/trunk/src/org/deegree/ogcwebservices/wfs/XMLFactory.java $ 002 /*---------------- FILE HEADER ------------------------------------------ 003 004 This file is part of deegree. 005 Copyright (C) 2001-2007 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 package org.deegree.ogcwebservices.wfs; 044 045 import java.io.IOException; 046 import java.net.URI; 047 import java.net.URL; 048 049 import org.deegree.datatypes.xlink.SimpleLink; 050 import org.deegree.enterprise.DeegreeParams; 051 import org.deegree.framework.log.ILogger; 052 import org.deegree.framework.log.LoggerFactory; 053 import org.deegree.framework.xml.XMLTools; 054 import org.deegree.i18n.Messages; 055 import org.deegree.model.filterencoding.capabilities.FilterCapabilities; 056 import org.deegree.model.metadata.iso19115.Keywords; 057 import org.deegree.model.metadata.iso19115.Linkage; 058 import org.deegree.model.metadata.iso19115.OnlineResource; 059 import org.deegree.model.spatialschema.Envelope; 060 import org.deegree.model.spatialschema.Position; 061 import org.deegree.ogcbase.CommonNamespaces; 062 import org.deegree.ogcwebservices.getcapabilities.DCPType; 063 import org.deegree.ogcwebservices.getcapabilities.HTTP; 064 import org.deegree.ogcwebservices.getcapabilities.MetadataURL; 065 import org.deegree.ogcwebservices.getcapabilities.OperationsMetadata; 066 import org.deegree.ogcwebservices.getcapabilities.Protocol; 067 import org.deegree.ogcwebservices.getcapabilities.ServiceIdentification; 068 import org.deegree.ogcwebservices.getcapabilities.ServiceProvider; 069 import org.deegree.ogcwebservices.wfs.capabilities.FeatureTypeList; 070 import org.deegree.ogcwebservices.wfs.capabilities.Operation; 071 import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilitiesDocument; 072 import org.deegree.ogcwebservices.wfs.capabilities.WFSFeatureType; 073 import org.deegree.ogcwebservices.wfs.capabilities.WFSOperationsMetadata; 074 import org.deegree.ogcwebservices.wfs.configuration.WFSConfiguration; 075 import org.w3c.dom.Element; 076 077 /** 078 * Responsible for the generation of XML representations of objects from the WFS context. 079 * 080 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a> 081 * 082 * @author last edited by: $Author:$ 083 * 084 * @version $Revision:$, $Date:$ 085 * 086 */ 087 088 public class XMLFactory_1_0_0 { 089 090 private static final URI WFSNS = CommonNamespaces.WFSNS; 091 092 private static final String PRE_WFS = CommonNamespaces.WFS_PREFIX + ":"; 093 094 private static final ILogger LOG = LoggerFactory.getLogger( XMLFactory_1_0_0.class ); 095 096 private static XMLFactory_1_0_0 factory = null; 097 098 /** 099 * @return a cached instance of this XMLFactory. 100 */ 101 public static synchronized XMLFactory_1_0_0 getInstance() { 102 if ( factory == null ) { 103 factory = new XMLFactory_1_0_0(); 104 } 105 return factory; 106 } 107 108 /** 109 * Exports a <code>WFSCapabilities</code> instance to a <code>WFSCapabilitiesDocument</code> with version 1_0. 110 * 111 * @param config 112 * @return DOM representation of the <code>WFSCapabilities</code> 113 * @throws IOException 114 * if XML template could not be loaded 115 */ 116 public WFSCapabilitiesDocument export( WFSConfiguration config ) { 117 118 WFSCapabilitiesDocument capabilitiesDocument = new WFSCapabilitiesDocument(); 119 120 capabilitiesDocument.createEmptyDocument( "1.0.0" ); 121 Element root = capabilitiesDocument.getRootElement(); 122 123 // Find the default online resource 124 DeegreeParams deegreeParams = config.getDeegreeParams(); 125 String defaultOnlineResource = "http://localhost:8080/deegree/services"; 126 if ( deegreeParams != null ) { 127 OnlineResource or = deegreeParams.getDefaultOnlineResource(); 128 if ( or != null ) { 129 Linkage link = or.getLinkage(); 130 if ( link != null ) { 131 URL uri = link.getHref(); 132 if ( uri != null ) { 133 String tmp = uri.toExternalForm(); 134 if ( !"".equals( tmp.toString() ) ) { 135 defaultOnlineResource = tmp; 136 } 137 } 138 } 139 } 140 } 141 142 ServiceIdentification serviceIdentification = config.getServiceIdentification(); 143 ServiceProvider serviceProvider = config.getServiceProvider(); 144 OperationsMetadata operationsMetadata = config.getOperationsMetadata(); 145 FeatureTypeList featureTypeList = config.getFeatureTypeList(); 146 147 if ( serviceIdentification != null ) { 148 String onlineResource = null; 149 if ( serviceProvider != null ) { 150 SimpleLink resource = serviceProvider.getProviderSite(); 151 URI online = resource.getHref(); 152 onlineResource = online.toASCIIString(); 153 } else { 154 onlineResource = defaultOnlineResource; 155 } 156 appendService( root, serviceIdentification, onlineResource ); 157 } 158 159 // Add the capabilities element 160 if ( operationsMetadata != null ) { 161 appendCapability( root, (WFSOperationsMetadata) operationsMetadata, defaultOnlineResource ); 162 } 163 164 if ( featureTypeList != null ) { 165 appendFeatureTypeList( root, featureTypeList ); 166 } 167 168 FilterCapabilities filterCapabilities = config.getFilterCapabilities(); 169 if ( filterCapabilities != null ) { 170 org.deegree.model.filterencoding.XMLFactory.appendFilterCapabilities100( root, filterCapabilities ); 171 } 172 return capabilitiesDocument; 173 } 174 175 /** 176 * Appends the DOM representation of the {@link ServiceIdentification} section to the passed {@link Element}. 177 * 178 * @param root 179 * to which to append the service section. 180 * @param serviceIdentification 181 * bean of the service identification element. 182 * @param onlineResource 183 * to be used as a default onlineResource. 184 */ 185 private void appendService( Element root, ServiceIdentification serviceIdentification, String onlineResource ) { 186 187 // 'Service'-element 188 Element service = XMLTools.appendElement( root, WFSNS, PRE_WFS + "Service" ); 189 190 // 'Name'-element 191 String tmpValue = serviceIdentification.getName(); 192 tmpValue = checkForEmptyValue( tmpValue, PRE_WFS + "Name", "WFS" ); 193 XMLTools.appendElement( service, WFSNS, PRE_WFS + "Name", tmpValue ); 194 195 tmpValue = serviceIdentification.getTitle(); 196 tmpValue = checkForEmptyValue( tmpValue, PRE_WFS + "Title", "A Web Feature Service" ); 197 XMLTools.appendElement( service, WFSNS, PRE_WFS + "Title", tmpValue ); 198 199 tmpValue = serviceIdentification.getAbstract(); 200 if ( tmpValue != null && "".equals( tmpValue.trim() ) ) { 201 XMLTools.appendElement( service, WFSNS, PRE_WFS + "Abstract", tmpValue ); 202 } 203 204 Keywords[] keywords = serviceIdentification.getKeywords(); 205 appendKeyWords( service, keywords ); 206 207 XMLTools.appendElement( service, WFSNS, PRE_WFS + "OnlineResource", onlineResource ); 208 209 tmpValue = serviceIdentification.getFees(); 210 if ( tmpValue == null || "".equals( tmpValue.trim() ) ) { 211 tmpValue = "NONE"; 212 } 213 XMLTools.appendElement( service, WFSNS, PRE_WFS + "Fees", tmpValue ); 214 215 String[] constraints = serviceIdentification.getAccessConstraints(); 216 StringBuffer sb = new StringBuffer(); 217 if ( constraints == null || constraints.length > 0 ) { 218 sb.append( "NONE" ); 219 } else { 220 for ( int i = 0; i < constraints.length; ++i ) { 221 String constraint = constraints[i]; 222 if ( constraint != null && "".equals( constraint.trim() ) ) { 223 sb.append( constraint ); 224 if ( ( i + 1 ) < constraints.length ) { 225 sb.append( " " ); 226 } 227 } 228 } 229 if ( sb.length() == 0 ) { 230 sb.append( "NONE" ); 231 } 232 } 233 XMLTools.appendElement( service, WFSNS, PRE_WFS + "AccessConstraints", sb.toString() ); 234 235 } 236 237 /** 238 * Appends the wfs:Capability element to the root element 239 * 240 * @param root 241 * @param operationsMetadata 242 */ 243 private void appendCapability( Element root, WFSOperationsMetadata operationsMetadata, String defaultOnlineResource ) { 244 Element capability = XMLTools.appendElement( root, WFSNS, PRE_WFS + "Capability" ); 245 Element request = XMLTools.appendElement( capability, WFSNS, PRE_WFS + "Request" ); 246 org.deegree.ogcwebservices.getcapabilities.Operation[] ops = operationsMetadata.getOperations(); 247 if ( ops != null && ops.length > 0 ) { 248 for ( org.deegree.ogcwebservices.getcapabilities.Operation op : ops ) { 249 String name = op.getName(); 250 if ( !( name == null || "".equals( name.trim() ) || "GetGMLObject".equals( name.trim() ) ) ) { 251 name = name.trim(); 252 253 254 Element operation = XMLTools.appendElement( request, WFSNS, PRE_WFS + name ); 255 if ( "DescribeFeatureType".equalsIgnoreCase( name ) ) { 256 Element sdl = XMLTools.appendElement( operation, WFSNS, PRE_WFS + "SchemaDescriptionLanguage" ); 257 XMLTools.appendElement( sdl, WFSNS, PRE_WFS + "XMLSCHEMA" ); 258 } else if ( "GetFeature".equalsIgnoreCase( name ) || "GetFeatureWithLock".equalsIgnoreCase( name ) ) { 259 Element resultFormat = XMLTools.appendElement( operation, WFSNS, PRE_WFS + "ResultFormat" ); 260 XMLTools.appendElement( resultFormat, WFSNS, PRE_WFS + "GML2" ); 261 } 262 DCPType[] dcpTypes = op.getDCPs(); 263 if ( dcpTypes != null && dcpTypes.length > 0 ) { 264 for ( DCPType dcpType : dcpTypes ) { 265 appendDCPType( operation, dcpType, defaultOnlineResource ); 266 } 267 } else { 268 appendDCPType( operation, null, defaultOnlineResource ); 269 } 270 } 271 } 272 } 273 274 } 275 276 /** 277 * Appends the XML representation of the <code>wfs:FeatureTypeList</code>- section to the passed 278 * <code>Element</code>. 279 * 280 * @param root 281 * @param featureTypeList 282 */ 283 private void appendFeatureTypeList( Element root, FeatureTypeList featureTypeList ) { 284 Element featureTypeListNode = XMLTools.appendElement( root, WFSNS, PRE_WFS + "FeatureTypeList" ); 285 Operation[] operations = featureTypeList.getGlobalOperations(); 286 if ( operations != null ) { 287 Element operationsNode = XMLTools.appendElement( featureTypeListNode, WFSNS, PRE_WFS + "Operations" ); 288 for ( int i = 0; i < operations.length; i++ ) { 289 XMLTools.appendElement( operationsNode, WFSNS, PRE_WFS + operations[i].getOperation() ); 290 } 291 } 292 WFSFeatureType[] featureTypes = featureTypeList.getFeatureTypes(); 293 if ( featureTypes != null ) { 294 for ( int i = 0; i < featureTypes.length; i++ ) { 295 appendWFSFeatureType( featureTypeListNode, featureTypes[i] ); 296 } 297 } 298 } 299 300 /** 301 * Appends the DCPType in the WFS namespace... pre-ows stuff. 302 * 303 * @param operation 304 * to add the dcptype to. 305 * @param type 306 * a bean containing necessary information if <code>null</code> a http-get/post dcp with the 307 * defaultonline resource will be inserted. 308 * @param defaultOnlineResource 309 * if no dcpType is given or no URL were inserted in the config, this will be inserted. 310 */ 311 private void appendDCPType( Element operation, DCPType type, String defaultOnlineResource ) { 312 Element dcpType = XMLTools.appendElement( operation, WFSNS, PRE_WFS + "DCPType" ); 313 Element http = XMLTools.appendElement( dcpType, WFSNS, PRE_WFS + "HTTP" ); 314 boolean appendDefaultProtocol = true; 315 if ( type != null ) { 316 Protocol pr = type.getProtocol(); 317 if ( pr != null ) { 318 if ( pr instanceof HTTP ) { 319 HTTP prot = (HTTP) pr; 320 URL[] getters = prot.getGetOnlineResources(); 321 URL[] posters = prot.getPostOnlineResources(); 322 if ( ( getters != null && getters.length > 0 ) ) { 323 for ( URL get : getters ) { 324 appendGetURL( http, get.toExternalForm() ); 325 } 326 } else { 327 appendGetURL( http, defaultOnlineResource ); 328 } 329 if ( posters != null && posters.length > 0 ) { 330 for ( URL post : posters ) { 331 appendPostURL( http, post.toExternalForm() ); 332 } 333 } else { 334 appendPostURL( http, defaultOnlineResource ); 335 } 336 appendDefaultProtocol = false; 337 } 338 } 339 } 340 if ( appendDefaultProtocol ) { 341 appendGetURL( http, defaultOnlineResource ); 342 appendPostURL( http, defaultOnlineResource ); 343 } 344 } 345 346 private void appendGetURL( Element http, String resourceURL ) { 347 Element get = XMLTools.appendElement( http, WFSNS, PRE_WFS + "Get" ); 348 get.setAttribute( "onlineResource", resourceURL ); 349 } 350 351 private void appendPostURL( Element http, String resourceURL ) { 352 Element post = XMLTools.appendElement( http, WFSNS, PRE_WFS + "Post" ); 353 post.setAttribute( "onlineResource", resourceURL ); 354 } 355 356 private void appendKeyWords( Element root, Keywords[] keywords ) { 357 if ( keywords != null && keywords.length > 0 ) { 358 StringBuffer sb = new StringBuffer(); 359 for ( int k = 0; k < keywords.length; ++k ) { 360 String[] words = keywords[k].getKeywords(); 361 if ( words != null && words.length > 0 ) { 362 for ( int i = 0; i < words.length; ++i ) { 363 sb.append( words[i] ); 364 if ( ( i + 1 ) < words.length ) { 365 sb.append( " " ); 366 } 367 } 368 } 369 if ( ( k + 1 ) < keywords.length ) { 370 sb.append( " " ); 371 } 372 } 373 XMLTools.appendElement( root, WFSNS, PRE_WFS + "Keywords", sb.toString() ); 374 } 375 } 376 377 /** 378 * Appends the XML representation of the <code>WFSFeatureType</code> instance to the passed <code>Element</code>. 379 * 380 * @param root 381 * @param featureType 382 */ 383 private void appendWFSFeatureType( Element root, WFSFeatureType featureType ) { 384 385 Element featureTypeNode = XMLTools.appendElement( root, WFSNS, PRE_WFS + "FeatureType" ); 386 387 if ( featureType.getName().getPrefix() != null ) { 388 XMLTools.appendNSBinding( featureTypeNode, featureType.getName().getPrefix(), featureType.getName() 389 .getNamespace() ); 390 } 391 XMLTools.appendElement( featureTypeNode, WFSNS, PRE_WFS + "Name", featureType.getName().getPrefixedName() ); 392 XMLTools.appendElement( featureTypeNode, WFSNS, PRE_WFS + "Title", featureType.getTitle() ); 393 String tmpValue = featureType.getAbstract(); 394 if ( tmpValue != null && !"".equals( tmpValue.trim() ) ) { 395 XMLTools.appendElement( featureTypeNode, WFSNS, PRE_WFS + "Abstract", tmpValue ); 396 } 397 Keywords[] keywords = featureType.getKeywords(); 398 appendKeyWords( featureTypeNode, keywords ); 399 400 URI defaultSrs = featureType.getDefaultSRS(); 401 if ( defaultSrs != null ) { 402 XMLTools.appendElement( featureTypeNode, WFSNS, PRE_WFS + "SRS", defaultSrs.toASCIIString() ); 403 } else if ( featureType.getOtherSrs() != null && featureType.getOtherSrs().length > 0 ) { 404 for ( URI srs : featureType.getOtherSrs() ) { 405 if ( srs != null ) { 406 XMLTools.appendElement( featureTypeNode, WFSNS, PRE_WFS + "SRS", srs.toASCIIString() ); 407 break; 408 } 409 } 410 } else { 411 // defaulting to EPSG:4326 is this correct???? 412 LOG.logDebug( "Found no default- or other-SRS, setting to EPGS:4326, is this correct?" ); 413 XMLTools.appendElement( featureTypeNode, WFSNS, PRE_WFS + "SRS", "EPSG:4326" ); 414 } 415 Operation[] operations = featureType.getOperations(); 416 if ( operations != null && operations.length > 0 ) { 417 for ( Operation op : operations ) { 418 if ( op != null && !"".equals( op.getOperation().trim() ) 419 && !"GetGMLObject".equalsIgnoreCase( op.getOperation().trim() ) ) { 420 Element opEl = XMLTools.appendElement( featureTypeNode, WFSNS, PRE_WFS + "Operations"); 421 XMLTools.appendElement( opEl, WFSNS, PRE_WFS + op.getOperation().trim()); 422 423 424 } 425 } 426 } 427 428 Envelope[] wgs84BoundingBoxes = featureType.getWgs84BoundingBoxes(); 429 for ( Envelope bbox : wgs84BoundingBoxes ) { 430 if ( bbox != null && bbox.getMin().getCoordinateDimension() == 2 ) { 431 Element latlon = XMLTools.appendElement( featureTypeNode, WFSNS, PRE_WFS + "LatLongBoundingBox" ); 432 Position min = bbox.getMin(); 433 Position max = bbox.getMax(); 434 latlon.setAttribute( "minx", Double.toString( min.getX() ) ); 435 latlon.setAttribute( "miny", Double.toString( min.getY() ) ); 436 latlon.setAttribute( "maxx", Double.toString( max.getX() ) ); 437 latlon.setAttribute( "maxy", Double.toString( max.getY() ) ); 438 } 439 } 440 MetadataURL[] mdURLs = featureType.getMetadataUrls(); 441 if ( mdURLs != null ) { 442 for ( MetadataURL mdURL : mdURLs ) { 443 if ( mdURL != null && mdURL.getOnlineResource() != null ) { 444 // first check if the format and type are acceptable. 445 String format = mdURL.getFormat(); 446 boolean formatOK = false; 447 if ( format != null && !"".equals( format.trim() ) ) { 448 format = format.trim(); 449 if ( "XML".equals( format ) || "SGML".equals( format ) || "TXT".equals( format ) ) { 450 formatOK = true; 451 } 452 } 453 454 String type = mdURL.getType(); 455 boolean typeOK = false; 456 if ( formatOK && type != null && !"".equals( type.trim() ) ) { 457 type = type.trim(); 458 if ( "TC211".equals( type ) || "FGDC".equals( type ) ) { 459 typeOK = true; 460 } 461 } 462 if ( formatOK && typeOK ) { 463 Element metadata = XMLTools.appendElement( featureTypeNode, 464 WFSNS, 465 PRE_WFS + "MetadataURL", 466 mdURL.getOnlineResource().toExternalForm() ); 467 metadata.setAttribute( "type", type ); 468 metadata.setAttribute( "format", format ); 469 } 470 } 471 } 472 } 473 } 474 475 private String checkForEmptyValue( String value, String elementName, String defaultValue ) { 476 if ( value == null || "".equals( value.trim() ) ) { 477 LOG.logError( Messages.getMessage( "WFS_MISSING_REQUIRED_ELEMENT", elementName ) ); 478 value = defaultValue; 479 } 480 return value; 481 } 482 }