001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/trunk/src/org/deegree/ogcwebservices/wfs/XMLFactory.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.wfs; 037 038 import static org.deegree.framework.xml.XMLTools.appendElement; 039 import static org.deegree.ogcbase.CommonNamespaces.OGCNS; 040 import static org.deegree.ogcbase.CommonNamespaces.OGC_PREFIX; 041 import static org.deegree.ogcbase.CommonNamespaces.WFS_PREFIX; 042 043 import java.io.IOException; 044 import java.io.StringReader; 045 import java.net.URI; 046 import java.net.URL; 047 import java.util.List; 048 049 import org.deegree.datatypes.QualifiedName; 050 import org.deegree.datatypes.xlink.SimpleLink; 051 import org.deegree.enterprise.DeegreeParams; 052 import org.deegree.framework.log.ILogger; 053 import org.deegree.framework.log.LoggerFactory; 054 import org.deegree.framework.util.StringTools; 055 import org.deegree.framework.xml.XMLFragment; 056 import org.deegree.framework.xml.XMLParsingException; 057 import org.deegree.framework.xml.XMLTools; 058 import org.deegree.i18n.Messages; 059 import org.deegree.io.datastore.FeatureId; 060 import org.deegree.model.filterencoding.Function; 061 import org.deegree.model.filterencoding.capabilities.FilterCapabilities; 062 import org.deegree.model.metadata.iso19115.Keywords; 063 import org.deegree.model.metadata.iso19115.Linkage; 064 import org.deegree.model.metadata.iso19115.OnlineResource; 065 import org.deegree.model.spatialschema.Envelope; 066 import org.deegree.model.spatialschema.Position; 067 import org.deegree.ogcbase.CommonNamespaces; 068 import org.deegree.ogcbase.PropertyPath; 069 import org.deegree.ogcbase.SortProperty; 070 import org.deegree.ogcwebservices.getcapabilities.DCPType; 071 import org.deegree.ogcwebservices.getcapabilities.HTTP; 072 import org.deegree.ogcwebservices.getcapabilities.MetadataURL; 073 import org.deegree.ogcwebservices.getcapabilities.OperationsMetadata; 074 import org.deegree.ogcwebservices.getcapabilities.Protocol; 075 import org.deegree.ogcwebservices.getcapabilities.ServiceIdentification; 076 import org.deegree.ogcwebservices.getcapabilities.ServiceProvider; 077 import org.deegree.ogcwebservices.wfs.capabilities.FeatureTypeList; 078 import org.deegree.ogcwebservices.wfs.capabilities.Operation; 079 import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilitiesDocument; 080 import org.deegree.ogcwebservices.wfs.capabilities.WFSFeatureType; 081 import org.deegree.ogcwebservices.wfs.capabilities.WFSOperationsMetadata; 082 import org.deegree.ogcwebservices.wfs.configuration.WFSConfiguration; 083 import org.deegree.ogcwebservices.wfs.operation.GetFeature; 084 import org.deegree.ogcwebservices.wfs.operation.GetFeatureDocument; 085 import org.deegree.ogcwebservices.wfs.operation.LockFeatureResponse; 086 import org.deegree.ogcwebservices.wfs.operation.Query; 087 import org.deegree.ogcwebservices.wfs.operation.GetFeature.RESULT_TYPE; 088 import org.deegree.ogcwebservices.wfs.operation.transaction.Insert; 089 import org.deegree.ogcwebservices.wfs.operation.transaction.InsertResults; 090 import org.deegree.ogcwebservices.wfs.operation.transaction.Transaction; 091 import org.deegree.ogcwebservices.wfs.operation.transaction.TransactionOperation; 092 import org.deegree.ogcwebservices.wfs.operation.transaction.TransactionResponse; 093 import org.deegree.ogcwebservices.wfs.operation.transaction.Update; 094 import org.w3c.dom.Document; 095 import org.w3c.dom.Element; 096 import org.w3c.dom.Text; 097 import org.xml.sax.SAXException; 098 099 /** 100 * Responsible for the generation of XML representations of objects from the WFS context that comply to WFS 101 * specification 1.0.0. 102 * 103 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a> 104 * @author last edited by: $Author:$ 105 * 106 * @version $Revision:$, $Date:$ 107 */ 108 public class XMLFactory_1_0_0 { 109 110 private static final URI WFSNS = CommonNamespaces.WFSNS; 111 112 // private static final String PRE_WFS = CommonNamespaces.WFS_PREFIX + ":"; 113 114 private static final ILogger LOG = LoggerFactory.getLogger( XMLFactory_1_0_0.class ); 115 116 private static XMLFactory_1_0_0 factory = null; 117 118 /** 119 * @return a cached instance of this XMLFactory. 120 */ 121 public static synchronized XMLFactory_1_0_0 getInstance() { 122 if ( factory == null ) { 123 factory = new XMLFactory_1_0_0(); 124 } 125 return factory; 126 } 127 128 /** 129 * Exports a <code>WFSCapabilities</code> instance to a <code>WFSCapabilitiesDocument</code> with version 1_0. 130 * 131 * @param config 132 * @return DOM representation of the <code>WFSCapabilities</code> 133 */ 134 public WFSCapabilitiesDocument export( WFSConfiguration config ) { 135 136 WFSCapabilitiesDocument capabilitiesDocument = new WFSCapabilitiesDocument(); 137 138 capabilitiesDocument.createEmptyDocument( "1.0.0" ); 139 Element root = capabilitiesDocument.getRootElement(); 140 141 // Find the default online resource 142 DeegreeParams deegreeParams = config.getDeegreeParams(); 143 String defaultOnlineResource = "http://localhost:8080/deegree/services"; 144 if ( deegreeParams != null ) { 145 OnlineResource or = deegreeParams.getDefaultOnlineResource(); 146 if ( or != null ) { 147 Linkage link = or.getLinkage(); 148 if ( link != null ) { 149 URL uri = link.getHref(); 150 if ( uri != null ) { 151 String tmp = uri.toExternalForm(); 152 if ( !"".equals( tmp.toString() ) ) { 153 defaultOnlineResource = tmp; 154 } 155 } 156 } 157 } 158 } 159 160 ServiceIdentification serviceIdentification = config.getServiceIdentification(); 161 ServiceProvider serviceProvider = config.getServiceProvider(); 162 OperationsMetadata operationsMetadata = config.getOperationsMetadata(); 163 FeatureTypeList featureTypeList = config.getFeatureTypeList(); 164 165 if ( serviceIdentification != null ) { 166 String onlineResource = null; 167 if ( serviceProvider != null ) { 168 SimpleLink resource = serviceProvider.getProviderSite(); 169 URI online = resource.getHref(); 170 onlineResource = online.toASCIIString(); 171 } else { 172 onlineResource = defaultOnlineResource; 173 } 174 appendService( root, serviceIdentification, onlineResource ); 175 } 176 177 // Add the capabilities element 178 if ( operationsMetadata != null ) { 179 appendCapability( root, (WFSOperationsMetadata) operationsMetadata, defaultOnlineResource ); 180 } 181 182 if ( featureTypeList != null ) { 183 appendFeatureTypeList( root, featureTypeList ); 184 } 185 186 FilterCapabilities filterCapabilities = config.getFilterCapabilities(); 187 if ( filterCapabilities != null ) { 188 org.deegree.model.filterencoding.XMLFactory.appendFilterCapabilities100( root, filterCapabilities ); 189 } 190 return capabilitiesDocument; 191 } 192 193 /** 194 * Appends the DOM representation of the {@link ServiceIdentification} section to the passed {@link Element}. 195 * 196 * @param root 197 * to which to append the service section. 198 * @param serviceIdentification 199 * bean of the service identification element. 200 * @param onlineResource 201 * to be used as a default onlineResource. 202 */ 203 private void appendService( Element root, ServiceIdentification serviceIdentification, String onlineResource ) { 204 205 // 'Service'-element 206 Element service = XMLTools.appendElement( root, WFSNS, "Service" ); 207 208 // 'Name'-element 209 String tmpValue = serviceIdentification.getName(); 210 tmpValue = checkForEmptyValue( tmpValue, "Name", "WFS" ); 211 XMLTools.appendElement( service, WFSNS, "Name", tmpValue ); 212 213 tmpValue = serviceIdentification.getTitle(); 214 tmpValue = checkForEmptyValue( tmpValue, "Title", "A Web Feature Service" ); 215 XMLTools.appendElement( service, WFSNS, "Title", tmpValue ); 216 217 tmpValue = serviceIdentification.getAbstract(); 218 if ( tmpValue != null && "".equals( tmpValue.trim() ) ) { 219 XMLTools.appendElement( service, WFSNS, "Abstract", tmpValue ); 220 } 221 222 Keywords[] keywords = serviceIdentification.getKeywords(); 223 appendKeyWords( service, keywords ); 224 225 XMLTools.appendElement( service, WFSNS, "OnlineResource", onlineResource ); 226 227 tmpValue = serviceIdentification.getFees(); 228 if ( tmpValue == null || "".equals( tmpValue.trim() ) ) { 229 tmpValue = "NONE"; 230 } 231 XMLTools.appendElement( service, WFSNS, "Fees", tmpValue ); 232 233 String[] constraints = serviceIdentification.getAccessConstraints(); 234 StringBuffer sb = new StringBuffer(); 235 if ( constraints == null || constraints.length > 0 ) { 236 sb.append( "NONE" ); 237 } else { 238 for ( int i = 0; i < constraints.length; ++i ) { 239 String constraint = constraints[i]; 240 if ( constraint != null && "".equals( constraint.trim() ) ) { 241 sb.append( constraint ); 242 if ( ( i + 1 ) < constraints.length ) { 243 sb.append( " " ); 244 } 245 } 246 } 247 if ( sb.length() == 0 ) { 248 sb.append( "NONE" ); 249 } 250 } 251 XMLTools.appendElement( service, WFSNS, "AccessConstraints", sb.toString() ); 252 253 } 254 255 /** 256 * Appends the wfs:Capability element to the root element 257 * 258 * @param root 259 * @param operationsMetadata 260 */ 261 private void appendCapability( Element root, WFSOperationsMetadata operationsMetadata, String defaultOnlineResource ) { 262 Element capability = XMLTools.appendElement( root, WFSNS, "Capability" ); 263 Element request = XMLTools.appendElement( capability, WFSNS, "Request" ); 264 org.deegree.ogcwebservices.getcapabilities.Operation[] ops = operationsMetadata.getOperations(); 265 if ( ops != null && ops.length > 0 ) { 266 for ( org.deegree.ogcwebservices.getcapabilities.Operation op : ops ) { 267 String name = op.getName(); 268 if ( !( name == null || "".equals( name.trim() ) || "GetGMLObject".equals( name.trim() ) ) ) { 269 name = name.trim(); 270 271 Element operation = XMLTools.appendElement( request, WFSNS, name ); 272 if ( "DescribeFeatureType".equalsIgnoreCase( name ) ) { 273 Element sdl = XMLTools.appendElement( operation, WFSNS, "SchemaDescriptionLanguage" ); 274 XMLTools.appendElement( sdl, WFSNS, "XMLSCHEMA" ); 275 } else if ( "GetFeature".equalsIgnoreCase( name ) || "GetFeatureWithLock".equalsIgnoreCase( name ) ) { 276 Element resultFormat = XMLTools.appendElement( operation, WFSNS, "ResultFormat" ); 277 XMLTools.appendElement( resultFormat, WFSNS, "GML2" ); 278 } 279 DCPType[] dcpTypes = op.getDCPs(); 280 if ( dcpTypes != null && dcpTypes.length > 0 ) { 281 for ( DCPType dcpType : dcpTypes ) { 282 appendDCPType( operation, dcpType, defaultOnlineResource ); 283 } 284 } else { 285 appendDCPType( operation, null, defaultOnlineResource ); 286 } 287 } 288 } 289 } 290 291 } 292 293 /** 294 * Appends the XML representation of the <code>wfs:FeatureTypeList</code>- section to the passed 295 * <code>Element</code>. 296 * 297 * @param root 298 * @param featureTypeList 299 */ 300 private void appendFeatureTypeList( Element root, FeatureTypeList featureTypeList ) { 301 Element featureTypeListNode = XMLTools.appendElement( root, WFSNS, "FeatureTypeList" ); 302 Operation[] operations = featureTypeList.getGlobalOperations(); 303 if ( operations != null ) { 304 Element operationsNode = XMLTools.appendElement( featureTypeListNode, WFSNS, "Operations" ); 305 for ( int i = 0; i < operations.length; i++ ) { 306 XMLTools.appendElement( operationsNode, WFSNS, operations[i].getOperation() ); 307 } 308 } 309 WFSFeatureType[] featureTypes = featureTypeList.getFeatureTypes(); 310 if ( featureTypes != null ) { 311 for ( int i = 0; i < featureTypes.length; i++ ) { 312 appendWFSFeatureType( featureTypeListNode, featureTypes[i] ); 313 } 314 } 315 } 316 317 /** 318 * Appends the DCPType in the WFS namespace... pre-ows stuff. 319 * 320 * @param operation 321 * to add the dcptype to. 322 * @param type 323 * a bean containing necessary information if <code>null</code> a http-get/post dcp with the 324 * defaultonline resource will be inserted. 325 * @param defaultOnlineResource 326 * if no dcpType is given or no URL were inserted in the config, this will be inserted. 327 */ 328 private void appendDCPType( Element operation, DCPType type, String defaultOnlineResource ) { 329 Element dcpType = XMLTools.appendElement( operation, WFSNS, "DCPType" ); 330 Element http = XMLTools.appendElement( dcpType, WFSNS, "HTTP" ); 331 boolean appendDefaultProtocol = true; 332 if ( type != null ) { 333 Protocol pr = type.getProtocol(); 334 if ( pr != null ) { 335 if ( pr instanceof HTTP ) { 336 HTTP prot = (HTTP) pr; 337 URL[] getters = prot.getGetOnlineResources(); 338 URL[] posters = prot.getPostOnlineResources(); 339 if ( ( getters != null && getters.length > 0 ) ) { 340 for ( URL get : getters ) { 341 appendGetURL( http, get.toExternalForm() ); 342 } 343 } else { 344 appendGetURL( http, defaultOnlineResource ); 345 } 346 if ( posters != null && posters.length > 0 ) { 347 for ( URL post : posters ) { 348 appendPostURL( http, post.toExternalForm() ); 349 } 350 } else { 351 appendPostURL( http, defaultOnlineResource ); 352 } 353 appendDefaultProtocol = false; 354 } 355 } 356 } 357 if ( appendDefaultProtocol ) { 358 appendGetURL( http, defaultOnlineResource ); 359 appendPostURL( http, defaultOnlineResource ); 360 } 361 } 362 363 private void appendGetURL( Element http, String resourceURL ) { 364 Element get = XMLTools.appendElement( http, WFSNS, "Get" ); 365 get.setAttribute( "onlineResource", resourceURL ); 366 } 367 368 private void appendPostURL( Element http, String resourceURL ) { 369 Element post = XMLTools.appendElement( http, WFSNS, "Post" ); 370 post.setAttribute( "onlineResource", resourceURL ); 371 } 372 373 private void appendKeyWords( Element root, Keywords[] keywords ) { 374 if ( keywords != null && keywords.length > 0 ) { 375 StringBuffer sb = new StringBuffer(); 376 for ( int k = 0; k < keywords.length; ++k ) { 377 String[] words = keywords[k].getKeywords(); 378 if ( words != null && words.length > 0 ) { 379 for ( int i = 0; i < words.length; ++i ) { 380 sb.append( words[i] ); 381 if ( ( i + 1 ) < words.length ) { 382 sb.append( " " ); 383 } 384 } 385 } 386 if ( ( k + 1 ) < keywords.length ) { 387 sb.append( " " ); 388 } 389 } 390 XMLTools.appendElement( root, WFSNS, "Keywords", sb.toString() ); 391 } 392 } 393 394 /** 395 * Appends the XML representation of the <code>WFSFeatureType</code> instance to the passed <code>Element</code>. 396 * 397 * @param root 398 * @param featureType 399 */ 400 private void appendWFSFeatureType( Element root, WFSFeatureType featureType ) { 401 402 Element featureTypeNode = XMLTools.appendElement( root, WFSNS, "FeatureType" ); 403 404 if ( featureType.getName().getPrefix() != null ) { 405 XMLTools.appendNSBinding( featureTypeNode, featureType.getName().getPrefix(), 406 featureType.getName().getNamespace() ); 407 } 408 XMLTools.appendElement( featureTypeNode, WFSNS, "Name", featureType.getName().getPrefixedName() ); 409 XMLTools.appendElement( featureTypeNode, WFSNS, "Title", featureType.getTitle() ); 410 String tmpValue = featureType.getAbstract(); 411 if ( tmpValue != null && !"".equals( tmpValue.trim() ) ) { 412 XMLTools.appendElement( featureTypeNode, WFSNS, "Abstract", tmpValue ); 413 } 414 Keywords[] keywords = featureType.getKeywords(); 415 appendKeyWords( featureTypeNode, keywords ); 416 417 URI defaultSrs = featureType.getDefaultSRS(); 418 if ( defaultSrs != null ) { 419 XMLTools.appendElement( featureTypeNode, WFSNS, "SRS", defaultSrs.toASCIIString() ); 420 } else if ( featureType.getOtherSrs() != null && featureType.getOtherSrs().length > 0 ) { 421 for ( URI srs : featureType.getOtherSrs() ) { 422 if ( srs != null ) { 423 XMLTools.appendElement( featureTypeNode, WFSNS, "SRS", srs.toASCIIString() ); 424 break; 425 } 426 } 427 } else { 428 // defaulting to EPSG:4326 is this correct???? 429 LOG.logDebug( "Found no default- or other-SRS, setting to EPGS:4326, is this correct?" ); 430 XMLTools.appendElement( featureTypeNode, WFSNS, "SRS", "EPSG:4326" ); 431 } 432 Operation[] operations = featureType.getOperations(); 433 if ( operations != null && operations.length > 0 ) { 434 Element opEl = XMLTools.appendElement( featureTypeNode, WFSNS, "Operations" ); 435 for ( Operation op : operations ) { 436 if ( op != null && !"".equals( op.getOperation().trim() ) 437 && !"GetGMLObject".equalsIgnoreCase( op.getOperation().trim() ) ) { 438 XMLTools.appendElement( opEl, WFSNS, op.getOperation().trim() ); 439 440 } 441 } 442 } 443 444 Envelope[] wgs84BoundingBoxes = featureType.getWgs84BoundingBoxes(); 445 for ( Envelope bbox : wgs84BoundingBoxes ) { 446 if ( bbox != null && bbox.getMin().getCoordinateDimension() == 2 ) { 447 Element latlon = XMLTools.appendElement( featureTypeNode, WFSNS, "LatLongBoundingBox" ); 448 Position min = bbox.getMin(); 449 Position max = bbox.getMax(); 450 latlon.setAttribute( "minx", Double.toString( min.getX() ) ); 451 latlon.setAttribute( "miny", Double.toString( min.getY() ) ); 452 latlon.setAttribute( "maxx", Double.toString( max.getX() ) ); 453 latlon.setAttribute( "maxy", Double.toString( max.getY() ) ); 454 } 455 } 456 MetadataURL[] mdURLs = featureType.getMetadataUrls(); 457 if ( mdURLs != null ) { 458 for ( MetadataURL mdURL : mdURLs ) { 459 if ( mdURL != null && mdURL.getOnlineResource() != null ) { 460 // first check if the format and type are acceptable. 461 String format = mdURL.getFormat(); 462 boolean formatOK = true; 463 if ( format != null ) { 464 if ( "text/xml".equals( format ) ) { 465 format = "XML"; 466 } else if ( "text/sgml".equals( format ) ) { 467 format = "SGML"; 468 } else if ( "text/plain".equals( format ) ) { 469 format = "TXT"; 470 } else { 471 formatOK = false; 472 } 473 } 474 475 String type = mdURL.getType(); 476 boolean typeOK = true; 477 if ( type != null ) { 478 if ( !( "TC211".equals( type ) || "FGDC".equals( type ) ) ) { 479 typeOK = false; 480 } 481 } 482 if ( formatOK && typeOK ) { 483 Element metadata = XMLTools.appendElement( featureTypeNode, WFSNS, "MetadataURL", 484 mdURL.getOnlineResource().toExternalForm() ); 485 metadata.setAttribute( "type", type ); 486 metadata.setAttribute( "format", format ); 487 } 488 } 489 } 490 } 491 } 492 493 private String checkForEmptyValue( String value, String elementName, String defaultValue ) { 494 if ( value == null || "".equals( value.trim() ) ) { 495 LOG.logError( Messages.getMessage( "WFS_MISSING_REQUIRED_ELEMENT", elementName ) ); 496 value = defaultValue; 497 } 498 return value; 499 } 500 501 /** 502 * @param response 503 * @return a WFS 1.0.0 style response 504 */ 505 public static XMLFragment export( TransactionResponse response ) { 506 507 XMLFragment doc = new XMLFragment( new QualifiedName( WFS_PREFIX, "WFS_TransactionResponse", WFSNS ) ); 508 509 Element root = doc.getRootElement(); 510 root.setAttribute( "version", "1.0.0" ); 511 512 if ( response.getInsertResults().size() > 0 ) { 513 Element e = appendElement( root, WFSNS, WFS_PREFIX + ":InsertResult" ); 514 // this is obviously not always correct, but it works around limitations in the test scripts... 515 e.setAttribute( "handle", response.getInsertResults().get( 0 ).getHandle() ); 516 for ( InsertResults res : response.getInsertResults() ) { 517 for ( FeatureId fid : res.getFeatureIDs() ) { 518 appendElement( e, OGCNS, OGC_PREFIX + ":FeatureId" ).setAttribute( "fid", fid.getAsString() ); 519 } 520 } 521 } 522 523 Element e = appendElement( root, WFSNS, WFS_PREFIX + ":TransactionResult" ); 524 List<Exception> exceptions = response.getExceptions(); 525 String status = exceptions == null || exceptions.size() == 0 ? "SUCCESS" : null; 526 527 if ( exceptions != null && exceptions.size() > 0 528 && ( response.getTotalDeleted() > 0 || response.getTotalInserted() > 0 || response.getTotalUpdated() > 0 ) ) { 529 status = "PARTIAL"; 530 } 531 if ( exceptions != null && exceptions.size() > 0 532 && ( response.getTotalDeleted() + response.getTotalInserted() + response.getTotalUpdated() == 0 ) ) { 533 status = "FAILED"; 534 } 535 536 if ( response.getTotalDeleted() + response.getTotalInserted() + response.getTotalUpdated() == 0 ) { 537 Transaction t = (Transaction) response.getRequest(); 538 boolean delOnly = true; 539 for ( TransactionOperation op : t.getOperations() ) { 540 if ( op instanceof Update || op instanceof Insert ) { 541 delOnly = false; 542 } 543 } 544 status = delOnly ? "SUCCESS" : "FAILED"; 545 } 546 547 e = appendElement( e, WFSNS, WFS_PREFIX + ":Status" ); 548 appendElement( e, WFSNS, WFS_PREFIX + ":" + ( status == null ? "FAILED" : status ) ); 549 550 return doc; 551 } 552 553 /** 554 * @param response 555 * @return a WFS 1.0.0 style lock feature response 556 */ 557 public static XMLFragment export( LockFeatureResponse response ) { 558 XMLFragment doc = new XMLFragment( new QualifiedName( WFS_PREFIX, "WFS_LockFeatureResponse", WFSNS ) ); 559 560 Element root = doc.getRootElement(); 561 562 appendElement( root, WFSNS, WFS_PREFIX + ":LockId", response.getLockId() ); 563 if ( response.getFeaturesLocked() != null && response.getFeaturesLocked().length > 0 ) { 564 Element e = appendElement( root, WFSNS, WFS_PREFIX + ":FeaturesLocked" ); 565 for ( String fid : response.getFeaturesLocked() ) { 566 appendElement( e, OGCNS, OGC_PREFIX + ":FeatureId" ).setAttribute( "fid", fid ); 567 } 568 } 569 if ( response.getFeaturesNotLocked() != null && response.getFeaturesNotLocked().length > 0 ) { 570 Element e = appendElement( root, WFSNS, WFS_PREFIX + ":FeaturesNotLocked" ); 571 for ( String fid : response.getFeaturesNotLocked() ) { 572 appendElement( e, OGCNS, OGC_PREFIX + ":FeatureId" ).setAttribute( "fid", fid ); 573 } 574 } 575 576 return doc; 577 } 578 579 /** 580 * Exports a <code>GetFeature</code> instance to a <code>GetFeatureDocument</code>. 581 * 582 * @param getFeature 583 * request to be exported 584 * @return XML representation of the <code>GetFeature</code> request 585 * @throws IOException 586 * @throws XMLParsingException 587 */ 588 public static GetFeatureDocument export( GetFeature getFeature ) 589 throws IOException, XMLParsingException { 590 591 GetFeatureDocument xml = new GetFeatureDocument(); 592 try { 593 xml.load( XMLFactory.class.getResource( "GetFeatureTemplate.xml" ) ); 594 } catch ( SAXException e ) { 595 throw new XMLParsingException( "could not parse GetFeatureTemplate.xml", e ); 596 } 597 Element root = xml.getRootElement(); 598 root.setAttribute( "outputFormat", getFeature.getOutputFormat() ); 599 root.setAttribute( "service", "WFS" ); 600 root.setAttribute( "version", getFeature.getVersion() ); 601 if ( getFeature.getHandle() != null ) { 602 root.setAttribute( "handle", getFeature.getHandle() ); 603 } 604 if ( getFeature.getResultType() == RESULT_TYPE.HITS ) { 605 root.setAttribute( "resultType", "hits" ); 606 } else { 607 root.setAttribute( "resultType", "results" ); 608 } 609 root.setAttribute( "maxFeatures", "" + getFeature.getMaxFeatures() ); 610 if ( getFeature.getStartPosition() > 0 ) { 611 root.setAttribute( "startPosition", "" + getFeature.getStartPosition() ); 612 } 613 if ( getFeature.getTraverseXLinkDepth() > 0 ) { 614 root.setAttribute( "traverseXLinkDepth", "" + getFeature.getTraverseXLinkDepth() ); 615 } 616 if ( getFeature.getTraverseXLinkExpiry() > 0 ) { 617 root.setAttribute( "traverseXLinkExpiry", "" + getFeature.getTraverseXLinkExpiry() ); 618 } 619 Query[] queries = getFeature.getQuery(); 620 for ( int i = 0; i < queries.length; i++ ) { 621 appendQuery( root, queries[i] ); 622 } 623 return xml; 624 } 625 626 /** 627 * Appends the XML representation of the given {@link Query} instance to an element. 628 * 629 * @param query 630 */ 631 private static void appendQuery( Element root, Query query ) 632 throws IOException, XMLParsingException { 633 634 Element queryElem = XMLTools.appendElement( root, WFSNS, "Query" ); 635 if ( query.getHandle() != null ) { 636 queryElem.setAttribute( "handle", query.getHandle() ); 637 } 638 if ( query.getFeatureVersion() != null ) { 639 queryElem.setAttribute( "featureVersion", query.getFeatureVersion() ); 640 } 641 QualifiedName[] qn = query.getTypeNames(); 642 String[] na = new String[qn.length]; 643 for ( int i = 0; i < na.length; i++ ) { 644 na[i] = qn[i].getPrefixedName(); 645 if ( qn[i].getNamespace() != null ) { 646 queryElem.setAttribute( "xmlns:" + qn[i].getPrefix(), qn[i].getNamespace().toASCIIString() ); 647 } 648 } 649 String tn = StringTools.arrayToString( na, ',' ); 650 queryElem.setAttribute( "typeName", tn ); 651 652 if ( query.getSrsName() != null ) { 653 queryElem.setAttribute( "srsName", query.getSrsName() ); 654 } 655 656 String[] aliases = query.getAliases(); 657 if ( aliases != null && aliases.length != 0 ) { 658 StringBuffer aliasesList = new StringBuffer( aliases[0] ); 659 for ( int i = 1; i < aliases.length; i++ ) { 660 aliasesList.append( ' ' ); 661 aliasesList.append( aliases[i] ); 662 } 663 queryElem.setAttribute( "aliases", aliasesList.toString() ); 664 } 665 666 PropertyPath[] propertyNames = query.getPropertyNames(); 667 for ( int i = 0; i < propertyNames.length; i++ ) { 668 Element propertyNameElement = appendElement( queryElem, OGCNS, OGC_PREFIX + ":PropertyName" ); 669 appendPropertyPath( propertyNameElement, propertyNames[i] ); 670 } 671 Function[] fn = query.getFunctions(); 672 // copy function definitions into query node 673 if ( fn != null ) { 674 for ( int i = 0; i < fn.length; i++ ) { 675 StringReader sr = new StringReader( fn[i].toXML().toString() ); 676 Document doc; 677 try { 678 doc = XMLTools.parse( sr ); 679 } catch ( SAXException e ) { 680 throw new XMLParsingException( "could not parse filter function", e ); 681 } 682 XMLTools.copyNode( doc.getDocumentElement(), queryElem ); 683 } 684 } 685 // copy filter into query node 686 if ( query.getFilter() != null ) { 687 StringReader sr = new StringReader( query.getFilter().to100XML().toString() ); 688 Document doc; 689 try { 690 doc = XMLTools.parse( sr ); 691 } catch ( SAXException e ) { 692 throw new XMLParsingException( "could not parse filter", e ); 693 } 694 Element elem = XMLTools.appendElement( queryElem, OGCNS, "ogc:Filter" ); 695 XMLTools.copyNode( doc.getDocumentElement(), elem ); 696 } 697 698 SortProperty[] sp = query.getSortProperties(); 699 if ( sp != null ) { 700 Element sortBy = XMLTools.appendElement( queryElem, OGCNS, "ogc:SortBy" ); 701 for ( int i = 0; i < sp.length; i++ ) { 702 Element sortProp = XMLTools.appendElement( sortBy, OGCNS, "ogc:SortProperty" ); 703 XMLTools.appendElement( sortProp, OGCNS, "ogc:PropertyName", sp[i].getSortProperty().getAsString() ); 704 if ( !sp[i].getSortOrder() ) { 705 XMLTools.appendElement( sortProp, OGCNS, "ogc:SortOrder", "DESC" ); 706 } 707 } 708 } 709 } 710 711 /** 712 * Appends the <code>DOM</code> representation of the given <code>PropertyPath</code> as a new text node to the 713 * given element (including necessary namespace bindings). 714 * 715 * @param element 716 * Element node where the PropertyPath is appended to 717 * @param propertyPath 718 */ 719 protected static void appendPropertyPath( Element element, PropertyPath propertyPath ) { 720 StringBuffer sb = new StringBuffer(); 721 sb.append( propertyPath ); 722 723 Text textNode = element.getOwnerDocument().createTextNode( sb.toString() ); 724 element.appendChild( textNode ); 725 XMLTools.appendNSBindings( element, propertyPath.getNamespaceContext() ); 726 } 727 }