001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/io/datastore/sql/wherebuilder/QueryTableTree.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.io.datastore.sql.wherebuilder;
037
038 import java.util.ArrayList;
039 import java.util.HashMap;
040 import java.util.List;
041 import java.util.Map;
042
043 import org.deegree.datatypes.QualifiedName;
044 import org.deegree.datatypes.Types;
045 import org.deegree.framework.log.ILogger;
046 import org.deegree.framework.log.LoggerFactory;
047 import org.deegree.i18n.Messages;
048 import org.deegree.io.datastore.PropertyPathResolvingException;
049 import org.deegree.io.datastore.schema.MappedFeaturePropertyType;
050 import org.deegree.io.datastore.schema.MappedFeatureType;
051 import org.deegree.io.datastore.schema.MappedGMLId;
052 import org.deegree.io.datastore.schema.MappedGMLSchema;
053 import org.deegree.io.datastore.schema.MappedGeometryPropertyType;
054 import org.deegree.io.datastore.schema.MappedPropertyType;
055 import org.deegree.io.datastore.schema.MappedSimplePropertyType;
056 import org.deegree.io.datastore.schema.TableRelation;
057 import org.deegree.io.datastore.schema.content.ConstantContent;
058 import org.deegree.io.datastore.schema.content.SimpleContent;
059 import org.deegree.io.datastore.sql.TableAliasGenerator;
060 import org.deegree.ogcbase.AnyStep;
061 import org.deegree.ogcbase.AttributeStep;
062 import org.deegree.ogcbase.CommonNamespaces;
063 import org.deegree.ogcbase.PropertyPath;
064 import org.deegree.ogcbase.PropertyPathStep;
065
066 /**
067 * Represents selected {@link MappedFeatureType}s and {@link PropertyPath} instances (properties used in an OGC filter
068 * and as sort criteria) and their mapping to a certain relational schema.
069 * <p>
070 * The requested {@link MappedFeatureType}s are the root nodes of the tree. If there is more than root node (feature
071 * type), the query requests a join between feature types.
072 *
073 * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </a>
074 * @author last edited by: $Author: mschneider $
075 *
076 * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
077 */
078 public class QueryTableTree {
079
080 private static final ILogger LOG = LoggerFactory.getLogger( QueryTableTree.class );
081
082 private TableAliasGenerator aliasGenerator;
083
084 private FeatureTypeNode[] roots;
085
086 // maps the aliases (specified in the query) to the corresponding FeatureTypeNode
087 private Map<String, FeatureTypeNode> ftAliasToRootFtNode = new HashMap<String, FeatureTypeNode>();
088
089 // uses 2 lists instead of Map, because PropertyPath.equals() is overwritten,
090 // and identity (==) is needed here (different occurences of "equal" PropertyName
091 // in filter must be treated as different PropertyPaths)
092 private List<PropertyPath> propertyPaths = new ArrayList<PropertyPath>();
093
094 private List<PropertyNode> propertyNodes = new ArrayList<PropertyNode>();
095
096 /**
097 * Creates a new instance of <code>QueryTableTree</code>.
098 *
099 * @param rootFts
100 * selected feature types, more than one type means that the types are joined
101 * @param aliases
102 * aliases for the feature types, may be null (must have same length as rootFts otherwise)
103 * @param aliasGenerator
104 * aliasGenerator to be used to generate table aliases, may be null
105 */
106 public QueryTableTree( MappedFeatureType[] rootFts, String[] aliases, TableAliasGenerator aliasGenerator ) {
107
108 if ( aliasGenerator != null ) {
109 this.aliasGenerator = aliasGenerator;
110 } else {
111 this.aliasGenerator = new TableAliasGenerator();
112 }
113 this.roots = new FeatureTypeNode[rootFts.length];
114 for ( int i = 0; i < rootFts.length; i++ ) {
115 FeatureTypeNode rootFtNode = new FeatureTypeNode( rootFts[i], aliases != null ? aliases[i] : null,
116 aliasGenerator.generateUniqueAlias() );
117 this.roots[i] = rootFtNode;
118 if ( aliases != null ) {
119 this.ftAliasToRootFtNode.put( aliases[i], rootFtNode );
120 LOG.logDebug( "Alias '" + aliases[i] + "' maps to '" + rootFtNode + "'." );
121 }
122 }
123 }
124
125 /**
126 * Returns the root feature type nodes of the tree.
127 *
128 * @return the root feature type nodes of the tree, contains at least one entry
129 */
130 public FeatureTypeNode[] getRootNodes() {
131 return this.roots;
132 }
133
134 /**
135 * Returns the alias for the root table.
136 *
137 * TODO support more than one root node
138 *
139 * @return the alias for the root table
140 */
141 public String getRootAlias() {
142 return this.roots[0].getTableAlias();
143 }
144
145 /**
146 * Returns the property node for the given property path.
147 *
148 * @param path
149 * property to be looked up
150 * @return the property node for the given property path
151 */
152 public PropertyNode getPropertyNode( PropertyPath path ) {
153
154 PropertyNode node = null;
155 for ( int i = 0; i < this.propertyPaths.size(); i++ ) {
156 if ( this.propertyPaths.get( i ) == path ) {
157 node = this.propertyNodes.get( i );
158 break;
159 }
160 }
161 return node;
162 }
163
164 /**
165 * Tries to insert the given {@link PropertyPath} as a filter criterion into the tree.
166 * <p>
167 * The {@link PropertyPath} is validated during insertion.
168 *
169 * @param property
170 * property to be inserted, has to have at least one step
171 * @throws PropertyPathResolvingException
172 * if the path violates the feature type's schema
173 */
174 public void addFilterProperty( PropertyPath property )
175 throws PropertyPathResolvingException {
176 MappedPropertyType pt = validate( property, false );
177 if ( pt instanceof MappedSimplePropertyType ) {
178 SimpleContent content = ( (MappedSimplePropertyType) pt ).getContent();
179 if ( content instanceof ConstantContent ) {
180 // add SimplePropertyNode to root node (because table path is irrelevant)
181 String[] tableAliases = generateTableAliases( pt );
182 PropertyNode propertyNode = new SimplePropertyNode( (MappedSimplePropertyType) pt, roots[0],
183 tableAliases );
184 this.propertyPaths.add( property );
185 this.propertyNodes.add( propertyNode );
186 // root.addPropertyNode( propertyNode );
187 } else {
188 insertValidatedPath( property );
189 }
190 } else {
191 insertValidatedPath( property );
192 }
193 }
194
195 /**
196 * Tries to insert the given {@link PropertyPath} as a sort criterion into the tree.
197 * <p>
198 * The {@link PropertyPath} is validated during insertion. It is also checked that the path is unique, i.e. every
199 * property type on the path must have maxOccurs set to 1.
200 *
201 * @param property
202 * property to be inserted, has to have at least one step
203 * @throws PropertyPathResolvingException
204 * if the path violates the feature type's schema
205 */
206 public void addSortProperty( PropertyPath property )
207 throws PropertyPathResolvingException {
208 MappedPropertyType pt = validate( property, false );
209 if ( pt instanceof MappedSimplePropertyType ) {
210 SimpleContent content = ( (MappedSimplePropertyType) pt ).getContent();
211 if ( content.isSortable() ) {
212 insertValidatedPath( property );
213 } else {
214 String msg = "Skipping property '" + property + "' as sort criterion.";
215 LOG.logDebug( msg );
216 // add SimplePropertyNode to root node (because table path is irrelevant)
217 String[] tableAliases = generateTableAliases( pt );
218 PropertyNode propertyNode = new SimplePropertyNode( (MappedSimplePropertyType) pt, roots[0],
219 tableAliases );
220 this.propertyPaths.add( property );
221 this.propertyNodes.add( propertyNode );
222 // root.addPropertyNode( propertyNode );
223 }
224 } else {
225 String msg = Messages.getMessage( "DATASTORE_PROPERTY_PATH_SORT1", property );
226 throw new PropertyPathResolvingException( msg );
227 }
228 }
229
230 /**
231 * Validates the (normalized) {@link PropertyPath} against the {@link MappedGMLSchema} and returns the
232 * {@link MappedPropertyType} that the path refers to.
233 *
234 * @param propertyPath
235 * PropertyPath to be validated, has to have at least one step
236 * @param forceUniquePath
237 * if set to true, an exeption is thrown if the path is not unique, i.e. at least one property on the
238 * path has maxOccurs set to a value > 1
239 * @return the property type that the path ends with
240 * @throws PropertyPathResolvingException
241 * if the path violates the feature type's schema
242 */
243 private MappedPropertyType validate( PropertyPath propertyPath, boolean forceUniquePath )
244 throws PropertyPathResolvingException {
245
246 MappedPropertyType endingPt = null;
247 MappedFeatureType currentFt = null;
248 int firstPropertyPos = 1;
249
250 // check if path starts with (valid) alias
251 QualifiedName firstStep = propertyPath.getStep( 0 ).getPropertyName();
252 LOG.logDebug( "Validating propertyPath.getStep( 0 ).getPropertyName(): " + firstStep );
253 if ( firstStep.getLocalName().startsWith( "$" ) ) {
254 LOG.logDebug( "The first step is an alias" );
255 // path starts with alias
256 String ftAlias = firstStep.getLocalName().substring( 1 );
257 FeatureTypeNode rootNode = this.ftAliasToRootFtNode.get( ftAlias );
258 if ( rootNode == null ) {
259 String msg = Messages.getMessage( "DATASTORE_PROPERTY_PATH_RESOLVE6", propertyPath,
260 firstStep.getLocalName() );
261 throw new PropertyPathResolvingException( msg );
262 }
263 currentFt = rootNode.getFeatureType();
264 } else {
265 // path does not start with an alias
266 if ( this.roots.length > 1 ) {
267 LOG.logDebug( "Multiple (join) feature type request. First step of '" + propertyPath
268 + "' must be the name (or an alias) of a requested feature type then..." );
269 QualifiedName ftName = propertyPath.getStep( 0 ).getPropertyName();
270 for ( FeatureTypeNode rootNode : this.roots ) {
271 if ( rootNode.getFeatureType().getName().equals( ftName ) ) {
272 currentFt = rootNode.getFeatureType();
273 break;
274 }
275 }
276 if ( currentFt == null ) {
277 String msg = Messages.getMessage( "DATASTORE_PROPERTY_PATH_RESOLVE5", propertyPath,
278 propertyPath.getStep( 0 ) );
279 throw new PropertyPathResolvingException( msg );
280 }
281 } else {
282 currentFt = this.roots[0].getFeatureType();
283 LOG.logDebug( "Single feature type request. Trying to validate '" + propertyPath
284 + "' against schema of feature type '" + currentFt.getName() + "'..." );
285
286 QualifiedName elementName = propertyPath.getStep( 0 ).getPropertyName();
287
288 // must be the name of the feature type or the name of a property of the feature
289 // type
290 if ( elementName.equals( currentFt.getName() ) ) {
291 LOG.logDebug( "First step matches the name of the feature type." );
292 } else {
293 LOG.logDebug( "First step does not match the name of the feature type. "
294 + "Must be the name of a property then." );
295 firstPropertyPos = 0;
296 }
297 }
298 }
299
300 for ( int step = firstPropertyPos; step < propertyPath.getSteps(); step += 2 ) {
301 LOG.logDebug( "Looking up property: " + propertyPath.getStep( step ).getPropertyName() );
302 endingPt = getPropertyType( currentFt, propertyPath.getStep( step ) );
303
304 if ( endingPt == null ) {
305 String msg = Messages.getMessage( "DATASTORE_PROPERTY_PATH_RESOLVE4", propertyPath, step,
306 propertyPath.getStep( step ), currentFt.getName(),
307 propertyPath.getStep( step ) );
308 throw new PropertyPathResolvingException( msg );
309 }
310
311 if ( forceUniquePath ) {
312 if ( endingPt.getMaxOccurs() != 1 ) {
313 String msg = Messages.getMessage( "DATASTORE_PROPERTY_PATH_SORT2", propertyPath, step,
314 endingPt.getName() );
315 throw new PropertyPathResolvingException( msg );
316 }
317 }
318
319 if ( endingPt instanceof MappedSimplePropertyType ) {
320 if ( step < propertyPath.getSteps() - 1 ) {
321 String msg = Messages.getMessage( "DATASTORE_PROPERTY_PATH_RESOLVE1", propertyPath, step,
322 endingPt.getName(), "simple" );
323 throw new PropertyPathResolvingException( msg );
324 }
325 } else if ( endingPt instanceof MappedGeometryPropertyType ) {
326 if ( step < propertyPath.getSteps() - 1 ) {
327 String msg = Messages.getMessage( "DATASTORE_PROPERTY_PATH_RESOLVE1", propertyPath, step,
328 endingPt.getName(), "geometry" );
329 throw new PropertyPathResolvingException( msg );
330 }
331 } else if ( endingPt instanceof MappedFeaturePropertyType ) {
332 if ( step == propertyPath.getSteps() - 1 ) {
333 String msg = Messages.getMessage( "DATASTORE_PROPERTY_PATH_RESOLVE2", propertyPath, step,
334 endingPt.getName() );
335 throw new PropertyPathResolvingException( msg );
336 }
337 MappedFeaturePropertyType pt = (MappedFeaturePropertyType) endingPt;
338 MappedFeatureType[] allowedTypes = pt.getFeatureTypeReference().getFeatureType().getConcreteSubstitutions();
339 QualifiedName givenTypeName = propertyPath.getStep( step + 1 ).getPropertyName();
340
341 // check if an alias is used
342 if ( givenTypeName.getLocalName().startsWith( "$" ) ) {
343 String ftAlias = givenTypeName.getLocalName().substring( 1 );
344 FeatureTypeNode ftNode = this.ftAliasToRootFtNode.get( ftAlias );
345 if ( ftNode == null ) {
346 String msg = Messages.getMessage( "DATASTORE_PROPERTY_PATH_RESOLVE6", propertyPath, step + 1,
347 propertyPath.getStep( step + 1 ) );
348 throw new PropertyPathResolvingException( msg );
349 }
350 givenTypeName = ftNode.getFeatureType().getName();
351 }
352
353 MappedFeatureType givenType = null;
354
355 for ( int i = 0; i < allowedTypes.length; i++ ) {
356 if ( allowedTypes[i].getName().equals( givenTypeName ) ) {
357 givenType = allowedTypes[i];
358 break;
359 }
360 }
361 if ( givenType == null ) {
362 StringBuffer validTypeList = new StringBuffer();
363 for ( int i = 0; i < allowedTypes.length; i++ ) {
364 validTypeList.append( '\'' );
365 validTypeList.append( allowedTypes[i].getName() );
366 validTypeList.append( '\'' );
367 if ( i != allowedTypes.length - 1 ) {
368 validTypeList.append( ", " );
369 }
370 }
371 String msg = Messages.getMessage( "DATASTORE_PROPERTY_PATH_RESOLVE3", propertyPath, step + 1,
372 propertyPath.getStep( step + 1 ), validTypeList );
373 throw new PropertyPathResolvingException( msg.toString() );
374 }
375 currentFt = pt.getFeatureTypeReference().getFeatureType();
376 } else {
377 assert ( false );
378 }
379 }
380 return endingPt;
381 }
382
383 /**
384 * Inserts the (already validated!!!) {@link PropertyPath} into the query tree.
385 *
386 * @see #validate(PropertyPath, boolean)
387 *
388 * @param propertyPath
389 * validated PropertyPath to be inserted into the tree
390 */
391 private void insertValidatedPath( PropertyPath propertyPath ) {
392
393 LOG.logDebug( "Inserting '" + propertyPath + "' into the query table tree." );
394
395 FeatureTypeNode ftNode = null;
396 int firstPropertyPos = 1;
397
398 // check if path starts with an alias
399 QualifiedName firstStep = propertyPath.getStep( 0 ).getPropertyName();
400 if ( firstStep.getLocalName().startsWith( "$" ) ) {
401 String ftAlias = firstStep.getLocalName().substring( 1 );
402 ftNode = this.ftAliasToRootFtNode.get( ftAlias );
403 } else {
404 if ( this.roots.length > 1 ) {
405 QualifiedName ftName = propertyPath.getStep( 0 ).getPropertyName();
406 for ( FeatureTypeNode rootNode : this.roots ) {
407 if ( rootNode.getFeatureType().getName().equals( ftName ) ) {
408 ftNode = rootNode;
409 break;
410 }
411 }
412 } else {
413 PropertyPathStep step = propertyPath.getStep( 0 );
414 QualifiedName elementName = step.getPropertyName();
415
416 // must be the name of the feature type or the name of a property of the feature type
417 if ( elementName.equals( this.roots[0].getFeatureType().getName() ) ) {
418 LOG.logDebug( "First step matches the name of the feature type." );
419 } else {
420 LOG.logDebug( "First step does not match the name of the feature type. "
421 + "Must be the name of a property then." );
422 firstPropertyPos = 0;
423 }
424 ftNode = this.roots[0];
425 }
426 }
427
428 PropertyNode propNode = null;
429 for ( int i = firstPropertyPos; i < propertyPath.getSteps(); i += 2 ) {
430
431 // check for property with step name in the feature type
432 MappedFeatureType currentFt = ftNode.getFeatureType();
433 MappedPropertyType pt = getPropertyType( currentFt, propertyPath.getStep( i ) );
434
435 // check if feature type node already has such a property node, add it otherwise
436 propNode = ftNode.getPropertyNode( pt );
437 if ( propNode == null || propNode.getProperty().getMaxOccurs() != 1 ) {
438 propNode = createPropertyNode( ftNode, pt );
439 ftNode.addPropertyNode( propNode );
440 }
441
442 if ( i + 1 < propertyPath.getSteps() ) {
443 // more steps? propNode must be a FeaturePropertyNode then
444 assert propNode instanceof FeaturePropertyNode;
445 QualifiedName featureStep = propertyPath.getStep( i + 1 ).getPropertyName();
446 ftNode = findOrAddSubFtNode( (FeaturePropertyNode) propNode, featureStep );
447 }
448 }
449
450 this.propertyPaths.add( propertyPath );
451 this.propertyNodes.add( propNode );
452
453 // // "equal" path is already registered, map this one to existing instance
454 // if ( getPropertyNode( propertyPath ) == null ) {
455 // this.propertyPaths.add( propertyPath );
456 // this.propertyNodes.add( propNode );
457 // }
458 }
459
460 private PropertyNode createPropertyNode( FeatureTypeNode ftNode, MappedPropertyType pt ) {
461
462 PropertyNode propNode = null;
463 if ( pt instanceof MappedSimplePropertyType ) {
464 String[] tableAliases = generateTableAliases( pt );
465 propNode = new SimplePropertyNode( (MappedSimplePropertyType) pt, ftNode, tableAliases );
466 } else if ( pt instanceof MappedGeometryPropertyType ) {
467 String[] tableAliases = generateTableAliases( pt );
468 propNode = new GeometryPropertyNode( (MappedGeometryPropertyType) pt, ftNode, tableAliases );
469 } else if ( pt instanceof MappedFeaturePropertyType ) {
470 String[] tableAliases = this.aliasGenerator.generateUniqueAliases( pt.getTableRelations().length - 1 );
471 propNode = new FeaturePropertyNode( ( (MappedFeaturePropertyType) pt ), ftNode, tableAliases );
472 } else {
473 assert ( false );
474 }
475 return propNode;
476 }
477
478 /**
479 * Returns a {@link FeatureTypeNode} that select a child of the given {@link FeaturePropertyNode}.
480 * <p>
481 * If the step specifies a feature type alias (instead of the feature type name), the corresponding root feature
482 * type node is returned.
483 *
484 * @param propNode
485 * @param featureStep
486 */
487 private FeatureTypeNode findOrAddSubFtNode( FeaturePropertyNode propNode, QualifiedName featureStep ) {
488
489 FeatureTypeNode childNode = null;
490
491 // check if step specifies an alias -> use corresponding root feature node then
492 if ( featureStep.getLocalName().startsWith( "$" ) ) {
493 String alias = featureStep.getLocalName().substring( 1 );
494 FeatureTypeNode[] childNodes = propNode.getFeatureTypeNodes();
495 for ( FeatureTypeNode node : childNodes ) {
496 if ( alias.equals( node.getFtAlias() ) ) {
497 childNode = node;
498 break;
499 }
500 }
501 if ( childNode == null ) {
502 childNode = this.ftAliasToRootFtNode.get( alias );
503 propNode.addFeatureTypeNode( childNode );
504 }
505 } else {
506 FeatureTypeNode[] subFtNodes = propNode.getFeatureTypeNodes();
507 for ( FeatureTypeNode node : subFtNodes ) {
508 if ( node.getFeatureType().getName().equals( featureStep ) ) {
509 childNode = node;
510 break;
511 }
512 }
513 if ( childNode == null ) {
514 MappedFeatureType subFt = this.roots[0].getFeatureType().getGMLSchema().getFeatureType( featureStep );
515 String tableAlias = this.aliasGenerator.generateUniqueAlias();
516 childNode = new FeatureTypeNode( subFt, null, tableAlias );
517 propNode.addFeatureTypeNode( childNode );
518 }
519 }
520
521 return childNode;
522 }
523
524 // private FeaturePropertyNode createFeaturePropertyNode( FeatureTypeNode ftNode, MappedFeaturePropertyType pt) {
525 //
526 // // MappedFeatureType[] allowedTypes = pt.getFeatureTypeReference().getFeatureType().getConcreteSubstitutions();
527 // // QualifiedName givenTypeName = propertyPath.getStep( step + 1 ).getPropertyName();
528 // // MappedFeatureType givenType = null;
529 //
530 //
531 // }
532
533 // private void addPathFragment( FeatureTypeNode ftNode, PropertyPath propertyPath, int startStep ) {
534 //
535 // for ( int step = startStep; step < propertyPath.getSteps(); step += 2 ) {
536 // LOG.logDebug( "Looking up property: " + propertyPath.getStep( step ).getPropertyName() );
537 // MappedPropertyType pt = getPropertyType( ftNode.getFeatureType(), propertyPath.getStep( step ) );
538 // if ( pt instanceof MappedSimplePropertyType ) {
539 // addSimplePropertyNode( ftNode, (MappedSimplePropertyType) pt, propertyPath, step );
540 // break;
541 // } else if ( pt instanceof MappedGeometryPropertyType ) {
542 // addGeometryPropertyNode( ftNode, (MappedGeometryPropertyType) pt, propertyPath, step );
543 // break;
544 // } else if ( pt instanceof MappedFeaturePropertyType ) {
545 // MappedFeaturePropertyType featurePT = (MappedFeaturePropertyType) pt;
546 // ftNode = addFeaturePropertyNode( ftNode, featurePT, propertyPath, step );
547 // } else {
548 // assert ( false );
549 // }
550 // }
551 // }
552
553 /**
554 * Returns the {@link MappedPropertyType} for the given {@link MappedFeatureType} that matches the given
555 * {@link PropertyPathStep}.
556 *
557 * @param ft
558 * @param step
559 * @return matching property type or null, if none exists
560 */
561 private MappedPropertyType getPropertyType( MappedFeatureType ft, PropertyPathStep step ) {
562
563 MappedPropertyType pt = null;
564 QualifiedName name = step.getPropertyName();
565
566 if ( step instanceof AttributeStep ) {
567 // TODO remove handling of gml:id here (after adaptation of feature model)
568 if ( CommonNamespaces.GMLNS.equals( name.getNamespace() ) && "id".equals( name.getLocalName() ) ) {
569 MappedGMLId gmlId = ft.getGMLId();
570 pt = new MappedSimplePropertyType( name, Types.VARCHAR, 1, 1, false, null, gmlId.getIdFields()[0] );
571 }
572 } else {
573 // normal property (not gml:id)
574 pt = (MappedPropertyType) ft.getProperty( name );
575
576 // quirk starts here
577 if ( pt == null && name.getNamespace() == null ) {
578 pt = (MappedPropertyType) ft.getProperty( name, true );
579 }
580 }
581
582 if ( pt == null && step instanceof AnyStep ) {
583 AnyStep as = (AnyStep) step;
584 if ( as.getIndex() != 0 ) {
585 pt = (MappedPropertyType) ft.getProperty( ft.getPropertyName( as.getIndex() - 1 ) );
586 } else {
587 pt = (MappedPropertyType) ft.getProperty( ft.getPropertyName( 0 ) );
588 }
589 }
590
591 return pt;
592 }
593
594 // private void addSimplePropertyNode( FeatureTypeNode featureTypeNode, MappedSimplePropertyType propertyType,
595 // PropertyPath propertyPath, int step ) {
596 //
597 // assert ( step == propertyPath.getSteps() - 1 );
598 // String[] tableAliases = generateTableAliases( propertyType );
599 // PropertyNode propertyNode = new SimplePropertyNode( propertyType, featureTypeNode, tableAliases );
600 // this.propertyPaths.add( propertyPath );
601 // this.propertyNodes.add( propertyNode );
602 // featureTypeNode.addPropertyNode( propertyNode );
603 // }
604 //
605 // private void addGeometryPropertyNode( FeatureTypeNode featureTypeNode, MappedGeometryPropertyType propertyType,
606 // PropertyPath propertyPath, int step ) {
607 //
608 // assert ( step == propertyPath.getSteps() - 1 );
609 // String[] tableAliases = generateTableAliases( propertyType );
610 // PropertyNode propertyNode = new GeometryPropertyNode( propertyType, featureTypeNode, tableAliases );
611 // this.propertyPaths.add( propertyPath );
612 // this.propertyNodes.add( propertyNode );
613 // featureTypeNode.addPropertyNode( propertyNode );
614 // }
615 //
616 // private FeatureTypeNode addFeaturePropertyNode( FeatureTypeNode ftNode, MappedFeaturePropertyType pt,
617 // PropertyPath propertyPath, int step ) {
618 //
619 // assert ( step < propertyPath.getSteps() - 1 );
620 // MappedFeatureType[] allowedTypes = pt.getFeatureTypeReference().getFeatureType().getConcreteSubstitutions();
621 // QualifiedName givenTypeName = propertyPath.getStep( step + 1 ).getPropertyName();
622 // MappedFeatureType givenType = null;
623 //
624 // for ( int i = 0; i < allowedTypes.length; i++ ) {
625 // if ( allowedTypes[i].getName().equals( givenTypeName ) ) {
626 // givenType = allowedTypes[i];
627 // break;
628 // }
629 // }
630 // assert ( givenType != null );
631 //
632 // // TODO make proper
633 // String[] tableAliases = this.aliasGenerator.generateUniqueAliases( pt.getTableRelations().length - 1 );
634 // String tableAlias = this.aliasGenerator.generateUniqueAlias();
635 // FeatureTypeNode childFeatureTypeNode = new FeatureTypeNode( givenType, null, tableAlias );
636 //
637 // FeatureType ft = pt.getFeatureTypeReference().getFeatureType();
638 // LOG.logDebug( "featureType: " + ft.getName() );
639 //
640 // PropertyNode propertyNode = new FeaturePropertyNode( pt, ftNode, tableAliases, childFeatureTypeNode );
641 // // this.propertyPaths.add (propertyPath);
642 // // this.propertyNodes.add (propertyNode);
643 // ftNode.addPropertyNode( propertyNode );
644 // return childFeatureTypeNode;
645 // }
646
647 private String[] generateTableAliases( MappedPropertyType pt ) {
648 String[] aliases = null;
649 TableRelation[] relations = pt.getTableRelations();
650 if ( relations != null ) {
651 aliases = new String[relations.length];
652 for ( int i = 0; i < aliases.length; i++ ) {
653 aliases[i] = this.aliasGenerator.generateUniqueAlias();
654 }
655 }
656 return aliases;
657 }
658
659 @Override
660 public String toString() {
661 StringBuffer sb = new StringBuffer();
662 for ( FeatureTypeNode root : this.roots ) {
663 sb.append( root.toString( "" ) );
664 sb.append( '\n' );
665 }
666 return sb.toString();
667 }
668 }