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