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