001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/ogcwebservices/wfs/operation/Query.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.operation; 037 038 import java.net.URI; 039 import java.util.Arrays; 040 041 import org.deegree.datatypes.QualifiedName; 042 import org.deegree.framework.log.ILogger; 043 import org.deegree.framework.log.LoggerFactory; 044 import org.deegree.framework.xml.XMLParsingException; 045 import org.deegree.model.filterencoding.ComparisonOperation; 046 import org.deegree.model.filterencoding.ComplexFilter; 047 import org.deegree.model.filterencoding.Filter; 048 import org.deegree.model.filterencoding.Function; 049 import org.deegree.model.filterencoding.LogicalOperation; 050 import org.deegree.model.filterencoding.Operation; 051 import org.deegree.model.filterencoding.PropertyIsBetweenOperation; 052 import org.deegree.model.filterencoding.PropertyIsCOMPOperation; 053 import org.deegree.model.filterencoding.PropertyIsInstanceOfOperation; 054 import org.deegree.model.filterencoding.PropertyIsLikeOperation; 055 import org.deegree.model.filterencoding.PropertyIsNullOperation; 056 import org.deegree.model.filterencoding.PropertyName; 057 import org.deegree.model.filterencoding.SpatialOperation; 058 import org.deegree.ogcbase.PropertyPath; 059 import org.deegree.ogcbase.PropertyPathStep; 060 import org.deegree.ogcbase.SortProperty; 061 import org.deegree.ogcwebservices.InvalidParameterValueException; 062 import org.deegree.ogcwebservices.wfs.WFService; 063 import org.deegree.ogcwebservices.wfs.operation.GetFeature.RESULT_TYPE; 064 import org.deegree.ogcwebservices.wfs.operation.GetFeatureDocument.BBoxTest; 065 import org.w3c.dom.Element; 066 067 /** 068 * Represents a <code>Query</code> operation as a part of a {@link GetFeature} request. 069 * 070 * Each individual query packaged in a {@link GetFeature} request is defined using the query value. The query value 071 * defines which feature type to query, what properties to retrieve and what constraints (spatial and non-spatial) to 072 * apply to those properties. 073 * <p> 074 * The mandatory <code>typeName</code> attribute is used to indicate the name of one or more feature type instances or 075 * class instances to be queried. Its value is a list of namespace-qualified names (XML Schema type QName, e.g. 076 * myns:School) whose value must match one of the feature types advertised in the Capabilities document of the WFS. 077 * Specifying more than one typename indicates that a join operation is being performed. All the names in the typeName 078 * list must be valid types that belong to this query's feature content as defined by the GML Application Schema. 079 * Optionally, individual feature type names in the typeName list may be aliased using the format QName=Alias. The 080 * following is an example typeName value that indicates that a join operation is to be performed and includes aliases: 081 * <BR> 082 * <code>typeName="ns1:InwaterA_1m=A,ns1:InwaterA_1m=B,ns2:CoastL_1M=C"</code><BR> 083 * This example encodes a join between three feature types aliased as A, B and C. The join between feature type A and B 084 * is a self-join. 085 * </p> 086 * 087 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a> 088 * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </a> 089 * @author last edited by: $Author: mschneider $ 090 * 091 * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $ 092 */ 093 public class Query { 094 095 private static ILogger LOG = LoggerFactory.getLogger( Query.class ); 096 097 private String handle; 098 099 private QualifiedName[] typeNames; 100 101 private String[] aliases; 102 103 private String featureVersion; 104 105 private String srsName; 106 107 private PropertyPath[] propertyNames; 108 109 private Function[] functions; 110 111 private Filter filter; 112 113 private SortProperty[] sortProperties; 114 115 // deegree specific extension ("inherited" from GetFeature container) 116 private RESULT_TYPE resultType; 117 118 // deegree specific extension ("inherited" from GetFeature container) 119 private int maxFeatures = -1; 120 121 // deegree specific extension ("inherited" from GetFeature container) 122 private int startPosition = 1; 123 124 private BBoxTest test; 125 126 /** 127 * @param propertyNames 128 * @param functions 129 * @param sortProperties 130 * @param handle 131 * @param featureVersion 132 * @param typeNames 133 * @param aliases 134 * @param srsName 135 * @param filter 136 * @param resultType 137 * @param maxFeatures 138 * @param startPosition 139 * @param test 140 */ 141 public Query( PropertyPath[] propertyNames, Function[] functions, SortProperty[] sortProperties, String handle, 142 String featureVersion, QualifiedName[] typeNames, String[] aliases, String srsName, Filter filter, 143 RESULT_TYPE resultType, int maxFeatures, int startPosition, BBoxTest test ) { 144 this( propertyNames, functions, sortProperties, handle, featureVersion, typeNames, aliases, srsName, filter, 145 resultType, maxFeatures, startPosition ); 146 147 this.test = test; 148 } 149 150 /** 151 * Creates a new <code>Query</code> instance. 152 * 153 * @param propertyNames 154 * names of the requested properties, may be null or empty 155 * @param functions 156 * names of the requested functions, may be null or empty 157 * @param sortProperties 158 * sort criteria, may be null or empty 159 * @param handle 160 * client-generated identifier for the query, may be null 161 * @param featureVersion 162 * version of the feature instances to fetched, may be null 163 * @param typeNames 164 * list of requested feature types 165 * @param aliases 166 * list of aliases for the feature types, must either be null or have the same length as the typeNames 167 * array 168 * @param srsName 169 * name of the spatial reference system 170 * @param filter 171 * spatial and none-spatial constraints 172 * @param resultType 173 * deegree specific extension ("inherited" from GetFeature container) 174 * @param maxFeatures 175 * deegree specific extension ("inherited" from GetFeature container) 176 * @param startPosition 177 * deegree specific extension ("inherited" from GetFeature container) 178 */ 179 public Query( PropertyPath[] propertyNames, Function[] functions, SortProperty[] sortProperties, String handle, 180 String featureVersion, QualifiedName[] typeNames, String[] aliases, String srsName, Filter filter, 181 RESULT_TYPE resultType, int maxFeatures, int startPosition ) { 182 if ( propertyNames == null ) { 183 this.propertyNames = new PropertyPath[0]; 184 // this.propertyNames[0] = new PropertyPath( typeNames[0] ); 185 } else { 186 this.propertyNames = propertyNames; 187 } 188 this.functions = functions; 189 this.sortProperties = sortProperties; 190 this.handle = handle; 191 this.featureVersion = featureVersion; 192 this.typeNames = typeNames; 193 this.aliases = aliases; 194 assert aliases == null || aliases.length == typeNames.length; 195 if ( LOG.isDebug() ) { 196 LOG.logDebug( "The query contains following aliases: " + Arrays.toString( aliases ) ); 197 } 198 this.srsName = srsName; 199 this.filter = filter; 200 this.resultType = resultType; 201 this.maxFeatures = maxFeatures; 202 this.startPosition = startPosition; 203 } 204 205 /** 206 * Creates a new <code>Query</code> instance. 207 * 208 * @param propertyNames 209 * names of the requested properties, may be null or empty 210 * @param functions 211 * names of the requested functions, may be null or empty 212 * @param sortProperties 213 * sort criteria, may be null or empty 214 * @param handle 215 * client-generated identifier for the query, may be null 216 * @param featureVersion 217 * version of the feature instances to fetched, may be null 218 * @param typeNames 219 * list of requested feature types. if more than one feature types is set a JOIN will be created (not yet 220 * supported) 221 * @param srsName 222 * name of the spatial reference system 223 * @param filter 224 * spatial and none-spatial constraints 225 * @param resultType 226 * deegree specific extension ("inherited" from GetFeature container) 227 * @param maxFeatures 228 * deegree specific extension ("inherited" from GetFeature container) 229 * @param startPosition 230 * deegree specific extension ("inherited" from GetFeature container) 231 * @return new <code>Query</code> instance 232 * @deprecated use create(PropertyPath[], Function[], SortProperty[], String, String, QualifiedName[], String[], 233 * String, Filter, int, int, RESULT_TYPE) instead 234 */ 235 @Deprecated 236 public static Query create( PropertyPath[] propertyNames, Function[] functions, SortProperty[] sortProperties, 237 String handle, String featureVersion, QualifiedName[] typeNames, String srsName, 238 Filter filter, int maxFeatures, int startPosition, RESULT_TYPE resultType ) { 239 return new Query( propertyNames, functions, sortProperties, handle, featureVersion, typeNames, null, srsName, 240 filter, resultType, maxFeatures, startPosition ); 241 } 242 243 /** 244 * Creates a new <code>Query</code> instance. 245 * 246 * @param propertyNames 247 * names of the requested properties, may be null or empty 248 * @param functions 249 * names of the requested functions, may be null or empty 250 * @param sortProperties 251 * sort criteria, may be null or empty 252 * @param handle 253 * client-generated identifier for the query, may be null 254 * @param featureVersion 255 * version of the feature instances to fetched, may be null 256 * @param typeNames 257 * list of requested feature types. if more than one feature types is set a JOIN will be created (not yet 258 * supported) 259 * @param aliases 260 * list of aliases for the feature types, must either be null or have the same length as the typeNames 261 * array 262 * @param srsName 263 * name of the spatial reference system 264 * @param filter 265 * spatial and none-spatial constraints 266 * @param resultType 267 * deegree specific extension ("inherited" from GetFeature container) 268 * @param maxFeatures 269 * deegree specific extension ("inherited" from GetFeature container) 270 * @param startPosition 271 * deegree specific extension ("inherited" from GetFeature container) 272 * @return new <code>Query</code> instance 273 */ 274 public static Query create( PropertyPath[] propertyNames, Function[] functions, SortProperty[] sortProperties, 275 String handle, String featureVersion, QualifiedName[] typeNames, String[] aliases, 276 String srsName, Filter filter, int maxFeatures, int startPosition, 277 RESULT_TYPE resultType ) { 278 return new Query( propertyNames, functions, sortProperties, handle, featureVersion, typeNames, aliases, 279 srsName, filter, resultType, maxFeatures, startPosition ); 280 } 281 282 /** 283 * Creates a new simple <code>Query</code> instance that selects the whole feature type. 284 * 285 * @param typeName 286 * name of the feature to be queried 287 * @return new <code>Query</code> instance 288 */ 289 public static Query create( QualifiedName typeName ) { 290 return new Query( null, null, null, null, null, new QualifiedName[] { typeName }, null, null, null, 291 RESULT_TYPE.RESULTS, -1, 0 ); 292 } 293 294 /** 295 * Creates a new simple <code>Query</code> instance that selects the whole feature type. 296 * 297 * @param typeName 298 * name of the feature to be queried 299 * @param filter 300 * spatial and none-spatial constraints 301 * @return new <code>Query</code> instance 302 */ 303 public static Query create( QualifiedName typeName, Filter filter ) { 304 return new Query( null, null, null, null, null, new QualifiedName[] { typeName }, null, null, filter, 305 RESULT_TYPE.RESULTS, -1, 0 ); 306 } 307 308 /** 309 * Creates a <code>Query</code> instance from a document that contains the DOM representation of the request, using 310 * the 1.1.0 filter encoding. 311 * <p> 312 * Note that the following attributes from the surrounding element are also considered (if it present): 313 * <ul> 314 * <li>resultType</li> 315 * <li>maxFeatures</li> 316 * <li>startPosition</li> 317 * </ul> 318 * 319 * @param element 320 * @return corresponding <code>Query</code> instance 321 * @throws XMLParsingException 322 */ 323 public static Query create( Element element ) 324 throws XMLParsingException { 325 return create( element, false ); 326 } 327 328 /** 329 * Creates a <code>Query</code> instance from a document that contains the DOM representation of the request. 330 * <p> 331 * Note that the following attributes from the surrounding element are also considered (if it present): 332 * <ul> 333 * <li>resultType</li> 334 * <li>maxFeatures</li> 335 * <li>startPosition</li> 336 * </ul> 337 * 338 * @param element 339 * @param useVersion_1_0_0 340 * if the filterencoding 1.0.0 rules should be applied. 341 * @return corresponding <code>Query</code> instance 342 * @throws XMLParsingException 343 */ 344 public static Query create( Element element, boolean useVersion_1_0_0 ) 345 throws XMLParsingException { 346 347 GetFeatureDocument doc = new GetFeatureDocument(); 348 Query query = doc.parseQuery( element, useVersion_1_0_0 ); 349 return query; 350 } 351 352 /** 353 * Returns the handle attribute. 354 * <p> 355 * The handle attribute is included to allow a client to associate a mnemonic name to the query. The purpose of the 356 * handle attribute is to provide an error handling mechanism for locating a statement that might fail. 357 * 358 * @return the handle attribute 359 */ 360 public String getHandle() { 361 return this.handle; 362 } 363 364 /** 365 * Returns the names of the requested feature types. 366 * 367 * @return the names of the requested feature types 368 */ 369 public QualifiedName[] getTypeNames() { 370 return this.typeNames; 371 } 372 373 /** 374 * Returns the aliases for the requested feature types. 375 * <p> 376 * The returned array is either null or has the same length as the array returned by {@link #getTypeNames()}. 377 * 378 * @see #getTypeNames() 379 * @return the aliases for the requested feature types, or null if no aliases are used 380 */ 381 public String[] getAliases() { 382 return this.aliases; 383 } 384 385 /** 386 * Returns the srsName attribute. 387 * 388 * @return the srsName attribute 389 */ 390 public String getSrsName() { 391 return this.srsName; 392 } 393 394 /** 395 * Sets the srsName attribute to given value. 396 * 397 * @param srsName 398 * name of the requested SRS 399 */ 400 public void setSrsName( String srsName ) { 401 this.srsName = srsName; 402 } 403 404 /** 405 * @throws InvalidParameterValueException 406 */ 407 public void performBBoxTest() 408 throws InvalidParameterValueException { 409 if ( test != null ) { 410 test.performTest(); 411 } 412 } 413 414 /** 415 * Sets the test to null, thus enabling the gc. 416 */ 417 public void deleteBBoxTest() { 418 test = null; 419 } 420 421 /** 422 * Returns the featureVersion attribute. 423 * 424 * The version attribute is included in order to accommodate systems that support feature versioning. A value of ALL 425 * indicates that all versions of a feature should be fetched. Otherwise an integer can be specified to return the n 426 * th version of a feature. The version numbers start at '1' which is the oldest version. If a version value larger 427 * than the largest version is specified then the latest version is return. The default action shall be for the 428 * query to return the latest version. Systems that do not support versioning can ignore the parameter and return 429 * the only version that they have. 430 * 431 * @return the featureVersion attribute 432 */ 433 public String getFeatureVersion() { 434 return this.featureVersion; 435 } 436 437 /** 438 * Returns all requested properties. 439 * 440 * @return all requested properties 441 * 442 * @see #getFunctions() 443 */ 444 public PropertyPath[] getPropertyNames() { 445 return this.propertyNames; 446 } 447 448 /** 449 * Beside property names a query may contains 0 to n functions modifying the values of one or more original 450 * properties. E.g. instead of area and population the density of a country can be requested by using a function 451 * instead: 452 * 453 * <pre> 454 * <ogc:Div> 455 * <ogc:PropertyName>population</ogc:PropertyName> 456 * <ogc:PropertyName>area</ogc:PropertyName> 457 * </ogc:Div> 458 * </pre> 459 * 460 * <p> 461 * If no functions and no property names are specified all properties should be fetched. 462 * </p> 463 * 464 * @return requested functions 465 * 466 * @see #getPropertyNames() 467 */ 468 public Function[] getFunctions() { 469 return this.functions; 470 } 471 472 /** 473 * Returns the filter that limits the query. 474 * 475 * @return the filter that limits the query 476 */ 477 public Filter getFilter() { 478 return this.filter; 479 } 480 481 /** 482 * Returns the sort criteria for the result. 483 * 484 * @return the sort criteria for the result 485 */ 486 public SortProperty[] getSortProperties() { 487 return this.sortProperties; 488 } 489 490 /** 491 * Returns the value of the resultType attribute ("inherited" from the GetFeature container). 492 * 493 * @return the value of the resultType attribute 494 */ 495 public RESULT_TYPE getResultType() { 496 return this.resultType; 497 } 498 499 /** 500 * Returns the value of the maxFeatures attribute ("inherited" from the GetFeature container). 501 * 502 * The optional maxFeatures attribute can be used to limit the number of features that a GetFeature request 503 * retrieves. Once the maxFeatures limit is reached, the result set is truncated at that point. If not limit is set 504 * -1 will be returned 505 * 506 * @return the value of the maxFeatures attribute 507 */ 508 public int getMaxFeatures() { 509 return this.maxFeatures; 510 } 511 512 /** 513 * @param maxFeatures 514 */ 515 public void setMaxFeatures( int maxFeatures ) { 516 this.maxFeatures = maxFeatures; 517 } 518 519 /** 520 * Returns the value of the startPosition attribute ("inherited" from the GetFeature container). 521 * <p> 522 * The startPosition parameter identifies the first result set entry to be returned. If no startPosition is set 523 * explicitly, 1 will be returned. 524 * 525 * @return the value of the startPosition attribute, 1 if undefined 526 */ 527 public int getStartPosition() { 528 return this.startPosition; 529 } 530 531 /** 532 * @see #getStartPosition() 533 * @param startPosition 534 */ 535 public void setStartPosition( int startPosition ) { 536 this.startPosition = startPosition; 537 } 538 539 /** 540 * Adds missing namespaces in the names of requested feature types. 541 * <p> 542 * If the {@link QualifiedName} of a requested type has a null namespace, the first qualified feature type name of 543 * the given {@link WFService} with the same local name is used instead. 544 * <p> 545 * Note: The method changes this request part (the feature type names) and should only be called by the 546 * <code>WFSHandler</code> class. 547 * 548 * @param wfs 549 * {@link WFService} instance that is used for the lookup of proper (qualified) feature type names 550 */ 551 public void guessMissingTypeNameNamespace( WFService wfs ) { 552 for ( int i = 0; i < typeNames.length; i++ ) { 553 QualifiedName typeName = typeNames[i]; 554 if ( typeName.getNamespace() == null ) { 555 if ( typeName.getLocalName().equals( typeName.getLocalName() ) ) { 556 LOG.logWarning( "Requested feature type name has no namespace information. Guessing namespace for feature type '" 557 + typeName.getLocalName() + "' (quirks lookup mode)." ); 558 for ( QualifiedName ftName : wfs.getMappedFeatureTypes().keySet() ) { 559 if ( ftName.getLocalName().equals( typeName.getLocalName() ) ) { 560 LOG.logWarning( "Using feature type '" + ftName + "'." ); 561 typeNames[i] = ftName; 562 break; 563 } 564 } 565 } 566 } 567 } 568 } 569 570 /** 571 * Adds missing namespaces to requested feature type names, property names, filter properties and sort properties. 572 * <p> 573 * Note: The method changes the request and should only be called by the <code>WFSHandler</code> class. 574 * 575 * @param wfs 576 * {@link WFService} instance that is used for the lookup of proper (qualified) feature and property 577 * names 578 */ 579 public void guessAllMissingNamespaces( WFService wfs ) { 580 guessMissingTypeNameNamespace( wfs ); 581 582 URI defaultNamespace = typeNames[0].getNamespace(); 583 augmentFilterWithNamespace( defaultNamespace ); 584 augmentSortPropertiesWithNamespace( defaultNamespace ); 585 augmentQueriedProperties( defaultNamespace ); 586 } 587 588 private void augmentQueriedProperties( URI defaultNamespace ) { 589 if ( propertyNames != null ) { 590 for ( PropertyPath propertyPath : propertyNames ) { 591 augmentPropertyPath( propertyPath, defaultNamespace ); 592 } 593 } 594 } 595 596 private void augmentSortPropertiesWithNamespace( URI defaultNamespace ) { 597 if ( sortProperties != null ) { 598 for ( SortProperty sortCriterion : sortProperties ) { 599 augmentPropertyPath( sortCriterion.getSortProperty(), defaultNamespace ); 600 } 601 } 602 } 603 604 private void augmentFilterWithNamespace( URI defaultNamespace ) { 605 if ( filter != null ) { 606 if ( filter instanceof ComplexFilter ) { 607 Operation operation = ( (ComplexFilter) filter ).getOperation(); 608 augmentFilterOperationWithNamespace( operation, defaultNamespace ); 609 } 610 } 611 } 612 613 private void augmentFilterOperationWithNamespace( Operation operation, URI defaultNamespace ) { 614 if ( operation instanceof ComparisonOperation ) { 615 if ( operation instanceof PropertyIsBetweenOperation ) { 616 PropertyIsBetweenOperation propOperation = (PropertyIsBetweenOperation) operation; 617 augmentPropertyPath( propOperation.getPropertyName().getValue(), defaultNamespace ); 618 if ( propOperation.getLowerBoundary() instanceof PropertyName ) { 619 augmentPropertyPath( ( (PropertyName) propOperation.getLowerBoundary() ).getValue(), 620 defaultNamespace ); 621 } 622 if ( propOperation.getUpperBoundary() instanceof PropertyName ) { 623 augmentPropertyPath( ( (PropertyName) propOperation.getUpperBoundary() ).getValue(), 624 defaultNamespace ); 625 } 626 } else if ( operation instanceof PropertyIsCOMPOperation ) { 627 PropertyIsCOMPOperation propOperation = (PropertyIsCOMPOperation) operation; 628 if ( propOperation.getFirstExpression() instanceof PropertyName ) { 629 augmentPropertyPath( ( (PropertyName) propOperation.getFirstExpression() ).getValue(), 630 defaultNamespace ); 631 } 632 if ( propOperation.getSecondExpression() instanceof PropertyName ) { 633 augmentPropertyPath( ( (PropertyName) propOperation.getSecondExpression() ).getValue(), 634 defaultNamespace ); 635 } 636 } else if ( operation instanceof PropertyIsInstanceOfOperation ) { 637 PropertyIsInstanceOfOperation propOperation = (PropertyIsInstanceOfOperation) operation; 638 augmentPropertyPath( propOperation.getPropertyName().getValue(), defaultNamespace ); 639 } else if ( operation instanceof PropertyIsLikeOperation ) { 640 PropertyIsLikeOperation propOperation = (PropertyIsLikeOperation) operation; 641 augmentPropertyPath( propOperation.getPropertyName().getValue(), defaultNamespace ); 642 } else if ( operation instanceof PropertyIsNullOperation ) { 643 PropertyIsNullOperation propOperation = (PropertyIsNullOperation) operation; 644 augmentPropertyPath( propOperation.getPropertyName().getValue(), defaultNamespace ); 645 } 646 } else if ( operation instanceof LogicalOperation ) { 647 LogicalOperation logicalOperation = (LogicalOperation) operation; 648 for ( Operation argument : logicalOperation.getArguments() ) { 649 augmentFilterOperationWithNamespace( argument, defaultNamespace ); 650 } 651 } else if ( operation instanceof SpatialOperation ) { 652 SpatialOperation spatialOperation = (SpatialOperation) operation; 653 PropertyName propertyName = spatialOperation.getPropertyName(); 654 if ( propertyName != null ) { 655 augmentPropertyPath( propertyName.getValue(), defaultNamespace ); 656 } 657 } 658 659 } 660 661 private void augmentPropertyPath( PropertyPath propertyPath, URI defaultNamespace ) { 662 for ( PropertyPathStep step : propertyPath.getAllSteps() ) { 663 QualifiedName name = step.getPropertyName(); 664 if ( name.getNamespace() == null ) { 665 LOG.logWarning( "Augmenting missing namespace: '" + name + "' -> '" + defaultNamespace + "'" ); 666 step.setPropertyName( new QualifiedName( name.getPrefix(), name.getLocalName(), defaultNamespace ) ); 667 } 668 } 669 } 670 671 /** 672 * Returns a string representation of the object. 673 * 674 * @return a string representation of the object 675 */ 676 @Override 677 public String toString() { 678 String ret = null; 679 ret = "propertyNames = " + propertyNames + "\n"; 680 ret += ( "handle = " + handle + "\n" ); 681 ret += ( "version = " + featureVersion + "\n" ); 682 ret += ( "typeName = " + typeNames + "\n" ); 683 ret += ( "filter = " + filter + "\n" ); 684 return ret; 685 } 686 }