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