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 }