001: /*
002: * Geotools2 - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2005-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: */
017:
018: package org.geotools.data.complex;
019:
020: import java.io.IOException;
021: import java.util.ArrayList;
022: import java.util.Arrays;
023: import java.util.HashMap;
024: import java.util.HashSet;
025: import java.util.Iterator;
026: import java.util.LinkedList;
027: import java.util.List;
028: import java.util.Map;
029: import java.util.Set;
030: import java.util.logging.Logger;
031:
032: import javax.xml.namespace.QName;
033:
034: import org.geotools.data.DefaultQuery;
035: import org.geotools.data.Query;
036: import org.geotools.data.complex.filter.XPath;
037: import org.geotools.data.complex.filter.XPath.Step;
038: import org.geotools.data.complex.filter.XPath.StepList;
039: import org.geotools.feature.iso.AttributeFactoryImpl;
040: import org.geotools.feature.iso.Types;
041: import org.geotools.filter.FilterAttributeExtractor;
042: import org.geotools.filter.FilterFactoryImplNamespaceAware;
043: import org.opengis.feature.Attribute;
044: import org.opengis.feature.ComplexAttribute;
045: import org.opengis.feature.Feature;
046: import org.opengis.feature.FeatureFactory;
047: import org.opengis.feature.type.AttributeDescriptor;
048: import org.opengis.feature.type.AttributeType;
049: import org.opengis.feature.type.Name;
050: import org.opengis.filter.FilterFactory;
051: import org.opengis.filter.expression.Expression;
052: import org.xml.sax.Attributes;
053: import org.xml.sax.helpers.NamespaceSupport;
054:
055: /**
056: *
057: * A Feature can be stored in many tables of database. Restoring that feature
058: * may be did by join, the resulting table can be explored using this iterator
059: * class. This iterator return Features with simple or complex attributes.
060: * <p>
061: * In the FeatureTypeMapping must be defined the grouping attributes, this value
062: * will be used to distinguish different features in the data sotore.
063: * </p>
064: * <p>
065: * The next can be a posible data store. <table>
066: * <tr>
067: * <td> station_no (string) </td>
068: * <td> sitename (string)</td>
069: * <td> anzlic_no (string)</td>
070: * <td> project_no (string)</td>
071: * <td> id (string)</td>
072: * <td> sample_collection_date (string)</td>
073: * <td> determinand_description (string)</td>
074: * <td> results_value (float)</td>
075: * <td> location (Point)</td>
076: * </tr>
077: * <tr>
078: * <td> station_1 </td>
079: * <td> sitename_1 </td>
080: * <td> anzlic_no_1 </td>
081: * <td> project_no_1 </td>
082: * <td> id_1_1 </td>
083: * <td> sample_collection_date_1_1 </td>
084: * <td> determinand_description_1_1 </td>
085: * <td> 1.1 </td>
086: * <td> POINT(1, 1) </td>
087: * </tr>
088: * <tr>
089: * <td> station_2 </td>
090: * <td> sitename_2 </td>
091: * <td> anzlic_no_2 </td>
092: * <td> project_no_2 </td>
093: * <td> id_2_1 </td>
094: * <td> sample_collection_date_2_1 </td>
095: * <td> determinand_description_2_1 </td>
096: * <td> 2.1 </td>
097: * <td> POINT(2, 2) </td>
098: * </tr>
099: * <tr>
100: * <td> station_2 </td>
101: * <td> sitename_2 </td>
102: * <td> anzlic_no_2 </td>
103: * <td> project_no_2 </td>
104: * <td> id_2_2 </td>
105: * <td> sample_collection_date_2_2 </td>
106: * <td> determinand_description_2_2 </td>
107: * <td> 2.2 </td>
108: * <td> POINT(2, 2) </td>
109: * </tr>
110: * <tr>
111: * <td colspan="9">...</td>
112: * </tr>
113: * <tr>
114: * <td> station_10 </td>
115: * <td> sitename_10 </td>
116: * <td> anzlic_no_10 </td>
117: * <td> project_no_10 </td>
118: * <td> id_10_10 </td>
119: * <td> sample_collection_date_10_9 </td>
120: * <td> determinand_description_10_9 </td>
121: * <td> 10.10 </td>
122: * <td> POINT(10, 10) </td>
123: * </tr>
124: * <tr>
125: * <td> station_10 </td>
126: * <td> sitename_10 </td>
127: * <td> anzlic_no_10 </td>
128: * <td> project_no_10 </td>
129: * <td> id_10_10 </td>
130: * <td> sample_collection_date_10_10 </td>
131: * <td> determinand_description_10_10 </td>
132: * <td> 10.10 </td>
133: * <td> POINT(10, 10) </td>
134: * </tr>
135: * </table>
136: * </p>
137: *
138: * @author Mauricio Pazos, Axios Engineering
139: * @author Gabriel Roldan, Axios Engineering
140: * @version $Id: GroupingFeatureIterator.java 27862 2007-11-12 19:51:19Z desruisseaux $
141: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/community-schemas/community-schema-ds/src/main/java/org/geotools/data/complex/GroupingFeatureIterator.java $
142: * @since 2.4
143: */
144: class GroupingFeatureIterator extends AbstractMappingFeatureIterator {
145: private static final Logger LOGGER = org.geotools.util.logging.Logging
146: .getLogger(GroupingFeatureIterator.class.getPackage()
147: .getName());
148:
149: /**
150: *
151: */
152: private Feature curSrcFeature;
153:
154: /**
155: * maxFeatures restriction value as provided by query
156: */
157: private int maxFeatures;
158:
159: /** counter to ensure maxFeatures is not exceeded */
160: private int featureCounter;
161:
162: /**
163: * flag to avoid fetching multiple source feature in repeated calld to
164: * hasNext() without calls to nex() in the middle
165: */
166: private boolean hasNextCalled;
167:
168: private List/* <String> */groupByAttributeNames;
169:
170: private List/* <AttributeMapping> */groupingMappings = new ArrayList();
171:
172: private List/* <AttributeMapping> */nonGroupingMappings = new ArrayList();
173:
174: private XPath xpathAttributeBuilder;
175:
176: /**
177: * Map of xpath target attributes/parent multivalued property. Used to
178: * recognize child properties of a multivalued and complex attributes and
179: * set their values for each member of the group.
180: */
181: private Map /* <StepList, XPath.Step> */multivaluedAttributePaths = new HashMap();
182:
183: private static final FeatureFactory attf = new AttributeFactoryImpl();
184:
185: /**
186: * New instance of GroupingFeatureIterator
187: *
188: * @param mapping
189: * @param query
190: * @param groupByAttributeNames
191: * list of attribute identifies for grouping the source feature
192: * @throws IOException
193: */
194: public GroupingFeatureIterator(ComplexDataStore store,
195: FeatureTypeMapping mappings, Query query)
196: throws IOException {
197: super (store, mappings, query);
198: if (mappings.getGroupByAttNames().size() == 0) {
199: throw new IllegalArgumentException(
200: "no grouping attributes defined");
201: }
202: groupByAttributeNames = mappings.getGroupByAttNames();
203:
204: xpathAttributeBuilder = new XPath();
205: xpathAttributeBuilder.setFeatureFactory(super .attf);
206: NamespaceSupport namespaces = mappings.getNamespaces();
207: // FilterFactory namespaceAwareFilterFactory =
208: // CommonFactoryFinder.getFilterFactory(hints);
209: FilterFactory namespaceAwareFilterFactory = new FilterFactoryImplNamespaceAware(
210: namespaces);
211: xpathAttributeBuilder
212: .setFilterFactory(namespaceAwareFilterFactory);
213:
214: // Extracts simple and complex mappings
215: List attrMappings = this .mapping.getAttributeMappings();
216:
217: splitMappings(attrMappings);
218: }
219:
220: protected Query getUnrolledQuery(Query query) {
221: maxFeatures = query.getMaxFeatures();
222: Query unmappedQuery = store.unrollQuery(query, mapping);
223: ((DefaultQuery) unmappedQuery)
224: .setMaxFeatures(Integer.MAX_VALUE);
225:
226: unmappedQuery = ensureGroupingAttsPresent(unmappedQuery);
227:
228: return unmappedQuery;
229: }
230:
231: /**
232: * Takes a Query and returns another one ensuring that all the grouping
233: * attributes are requested, in order to be able of producing the correct
234: * number of output features, for example, from a joined set of tables.
235: *
236: * @param query
237: * @return
238: */
239: private Query ensureGroupingAttsPresent(Query query) {
240: if (query.retrieveAllProperties()) {
241: return query;
242: }
243:
244: groupByAttributeNames = super .mapping.getGroupByAttNames();
245: DefaultQuery neededQuery = new DefaultQuery(query);
246: List requestedAtts = Arrays.asList(query.getPropertyNames());
247: if (!requestedAtts.containsAll(this .groupByAttributeNames)) {
248: List remaining = new ArrayList(groupByAttributeNames);
249: remaining.removeAll(requestedAtts);
250: GroupingFeatureIterator.LOGGER
251: .fine("Adding missing grouping atts: " + remaining);
252:
253: List queryAtts = new ArrayList(remaining);
254: queryAtts.addAll(requestedAtts);
255:
256: neededQuery.setPropertyNames(queryAtts);
257: }
258: return neededQuery;
259: }
260:
261: /**
262: * @return boolean true if exist next feature, false in other case.
263: */
264: public final boolean hasNext() {
265: if (hasNextCalled) {
266: return curSrcFeature != null;
267: }
268:
269: boolean exists = false;
270:
271: if (featureCounter < maxFeatures) {
272:
273: exists = this .sourceFeatures.hasNext();
274:
275: if (exists && this .curSrcFeature == null) {
276: this .curSrcFeature = (Feature) this .sourceFeatures
277: .next();
278: }
279: }
280:
281: if (!exists) {
282: GroupingFeatureIterator.LOGGER
283: .finest("no more features, produced "
284: + featureCounter);
285: }
286:
287: hasNextCalled = true;
288:
289: return exists;
290: }
291:
292: /**
293: * @return Feature the next feature.
294: */
295: public final Object /* Feature */next() {
296: if (!hasNext()) {
297: throw new IllegalStateException(
298: "there are no more features in this iterator");
299: }
300: //note hasNextCalled is going to be updated in createCurrentGroup()
301: //as it might be called directly to improve performance in
302: //calculating the resultset size
303: Feature next = computeNext();
304: ++featureCounter;
305: return next;
306: }
307:
308: /**
309: * Makes a Complex Feature using the data source and grouping the field of
310: * mapped features. The source Features can be a Simple or Complex,
311: * furthermore an attribute of target Feature can be in one or more Source
312: * Features.
313: * <p>
314: * The target (mapped) attributes are created in the order defined in the
315: * {@linkplain FeatureTypeMapping}'s attribute mappings.
316: * </p>
317: *
318: * @return a Feature of the target FeatureType composed up of applying the
319: * mappings and groupings defined in the
320: * {@linkplain FeatureTypeMapping}
321: */
322: private Feature computeNext() {
323: // get the mapping set of a feature attribute
324: final AttributeDescriptor targetNode = mapping
325: .getTargetFeature();
326: final Name targetNodeName = targetNode.getName();
327: final List attMappings = mapping.getAttributeMappings();
328:
329: String fid = extractIdForFeature(curSrcFeature);
330:
331: // create the target feature and iterate in the source for set its
332: // values.
333: final Feature targetFeature = GroupingFeatureIterator.attf
334: .createFeature(null, targetNode, fid);
335:
336: final Feature featureForGroupingAtts = this .curSrcFeature;
337:
338: final List/* <Feature> */currentGroup = createCurrentGroup();
339:
340: /**
341: * We need to set attributes in the attribute mapping's declared order
342: */
343: for (Iterator itr = attMappings.iterator(); itr.hasNext();) {
344: AttributeMapping mapping = (AttributeMapping) itr.next();
345: StepList targetXPath = mapping.getTargetXPath();
346: if (targetXPath.size() == 1) {
347: Step rootStep = (Step) targetXPath.get(0);
348: QName stepName = rootStep.getName();
349: if (Types.equals(targetNodeName, stepName)) {
350: // ignore the top level mapping for the Feature
351: // itself
352: // as it was already set
353: continue;
354: }
355: }
356:
357: if (mapping.isMultiValued()) {
358: setMultivaluedAttribute(targetFeature, mapping,
359: currentGroup);
360: } else {
361: setSingleValuedAttribute(targetFeature,
362: featureForGroupingAtts, mapping, currentGroup);
363: }
364: }
365:
366: return targetFeature;
367: }
368:
369: /**
370: * Iterate over the source features while they belong to the same set of
371: * grouping attributes.
372: *
373: * <p>
374: * Each time this method is called {@link #hasNextCalled} is set to false
375: * </p>
376: *
377: * @return the set of Features from the source resultset that belongs to the
378: * same group.
379: */
380: List/* <Feature> */createCurrentGroup() {
381: List/* <List<Attribute>> */curGroupingAttrList = extractGroupingAttributes(this .curSrcFeature);
382: List/* <Feature> */currentGroup = new LinkedList/* <Feature> */();
383: currentGroup.add(this .curSrcFeature);
384:
385: // loop control: break, if has not next or grouping attributes of
386: // next feature are diferent
387: hasNextCalled = false;
388:
389: while (this .sourceFeatures.hasNext()) {
390: this .curSrcFeature = (Feature) this .sourceFeatures.next();
391: List/* <List<Attribute>> */newGroupingAttrList = extractGroupingAttributes(this .curSrcFeature);
392: if (!curGroupingAttrList.equals(newGroupingAttrList)) {
393: hasNextCalled = true;
394: break;
395: }
396: currentGroup.add(this .curSrcFeature);
397: }
398: return currentGroup;
399: // [[Attribute[station_no:station_no:@:station_no.2]],
400: // [Attribute[sitename:sitename:@:sitename2]],
401: // [Attribute[anzlic_no:anzlic_no:@:anzlic_no2]],
402: // [Attribute[project_no:project_no:@:project_no2]],
403: // [Attribute[location:location:@:POINT (2 2)]]]
404: // [[Attribute[station_no:station_no:@:station_no.2]],
405: // [Attribute[sitename:sitename:@:sitename2]],
406: // [Attribute[anzlic_no:anzlic_no:@:anzlic_no2]],
407: // [Attribute[project_no:project_no:@:project_no2]],
408: // [Attribute[location:location:@:POINT (2 2)]]]
409: }
410:
411: /**
412: * Sets the values of grouping attributes.
413: *
414: * @param sourceFeature
415: * @param groupingMappings
416: * @param targetFeature
417: *
418: * @return Feature. Target feature sets with simple attributes
419: */
420: private void setSingleValuedAttribute(Feature target,
421: final Feature source, final AttributeMapping attMapping,
422: final List /* <Feature> */currentGroup) {
423:
424: Expression expression = attMapping.getSourceExpression();
425: final AttributeType targetNodeType = attMapping
426: .getTargetNodeInstance();
427: final StepList xpath = attMapping.getTargetXPath();
428:
429: if (expression == null) {
430: expression = Expression.NIL;
431: }
432:
433: List parentMultivaluedAttributePath = (List) multivaluedAttributePaths
434: .get(xpath);
435: Object value;
436: if (parentMultivaluedAttributePath != null) {
437: final int parentIndex = parentMultivaluedAttributePath
438: .size() - 1;
439: int index = 0;
440:
441: for (Iterator it = currentGroup.iterator(); it.hasNext();) {
442: index++;
443: Feature sourceFeature = (Feature) it.next();
444: try {
445: value = getValue(expression, sourceFeature);
446: } catch (Exception e) {
447: // HACK: what we actually need to resolve is dealing
448: // with queries that restricts the attributes returned
449: // by the source featurestore
450: continue;
451: }
452:
453: String id = extractIdForAttribute(attMapping
454: .getIdentifierExpression(), sourceFeature);
455:
456: StepList childSteps = setIndexAtStep(xpath, index,
457: parentIndex);
458:
459: Attribute instance = xpathAttributeBuilder.set(target,
460: childSteps, value, id, targetNodeType);
461: Map clientPropsMappings = attMapping
462: .getClientProperties();
463: setClientProperties(instance, sourceFeature,
464: clientPropsMappings);
465: }
466: } else {
467:
468: try {
469: value = getValue(expression, source);
470:
471: //TODO - check we dont actually need to bind to explicit null value at some point
472: //TODO: bouble ckeck: commented out the following two lines since it was causing
473: //attributes set through <targetAttributeNode> not to work (as the actual instance type
474: //were not being set by returning early)
475: // if ( value == null )
476: // return;
477:
478: // if target has id construct the id value from source
479: String id = extractIdForAttribute(attMapping
480: .getIdentifierExpression(), this .curSrcFeature);
481: Attribute instance = xpathAttributeBuilder.set(target,
482: xpath, value, id, targetNodeType);
483: Map clientPropsMappings = attMapping
484: .getClientProperties();
485: setClientProperties(instance, curSrcFeature,
486: clientPropsMappings);
487:
488: } catch (Exception e) {
489: // HACK: what we actually need to resolve is dealing
490: // with queries that restricts the attributes returned
491: // by the source featurestore
492: if (e instanceof RuntimeException) {
493: throw (RuntimeException) e;
494: } else {
495: throw (RuntimeException) new RuntimeException()
496: .initCause(e);
497: }
498: }
499: }
500:
501: }
502:
503: /**
504: * Sets values of compex attributes, meaning those that are marked by the
505: * {@link AttributeMapping#isMultiValued() multivalued flag} on the
506: * attribute mapping.
507: *
508: * @param sourceFeature
509: * @param complexAttrMappings
510: * @param targetFeature
511: *
512: * @return Feature target feature sets with complex attributes
513: */
514: private void setMultivaluedAttribute(Feature target,
515: AttributeMapping attMapping, List/* <Feature> */group) {
516:
517: Expression sourceExpression = attMapping.getSourceExpression();
518: final AttributeType targetNodeType = attMapping
519: .getTargetNodeInstance();
520: final StepList targetXpath = attMapping.getTargetXPath();
521:
522: int index = 0;
523: Object value;
524: for (Iterator itr = group.iterator(); itr.hasNext();) {
525: Feature sourceFeature = (Feature) itr.next();
526: try {
527: value = getValue(sourceExpression, sourceFeature);
528: } catch (Exception e) {
529: // HACK: what we actually need to resolve is dealing
530: // with queries that restricts the attributes returned
531: // by the source featurestore
532: continue;
533: }
534: index++;
535: // if target has id construct the id value from source
536: String id = extractIdForAttribute(attMapping
537: .getIdentifierExpression(), sourceFeature);
538:
539: // if complex or leaf of complex attribute then insert index in
540: // xpath.
541: StepList targetXpathAttr = null;
542:
543: targetXpathAttr = setIndexOfLastStep(target, targetXpath,
544: index);
545: // boolean isComplexType =
546: // xpathAttributeBuilder.isComplexType(targetXpath, target
547: // .getDescriptor());
548: // if (isComplexType) {
549: // targetXpathAttr = setIndexOfLastStep(target, targetXpath, index);
550: //
551: // } else if (isLeafOfNestedComplexType(targetXpath,
552: // target.getDescriptor())) {
553: // targetXpathAttr = setLeafInexInXPathExpression(target,
554: // targetXpath, index);
555: // } else {
556: // throw new IllegalArgumentException(
557: // "Attribute must be complex type or belong to the grouping
558: // attributes");
559: // }
560:
561: Attribute instance = xpathAttributeBuilder.set(target,
562: targetXpathAttr, value, id, targetNodeType);
563: Map clientPropsMappings = attMapping.getClientProperties();
564: setClientProperties(instance, sourceFeature,
565: clientPropsMappings);
566: }
567: }
568:
569: private void setClientProperties(Attribute target, Feature source,
570: Map clientProperties) {
571: if (clientProperties.size() == 0) {
572: return;
573: }
574:
575: final Map nodeAttributes = new HashMap();
576: final AttributeDescriptor node = target.getDescriptor();
577:
578: for (Iterator it = clientProperties.entrySet().iterator(); it
579: .hasNext();) {
580: Map.Entry entry = (Map.Entry) it.next();
581: org.opengis.feature.type.Name propName = (org.opengis.feature.type.Name) entry
582: .getKey();
583: Expression propExpr = (Expression) entry.getValue();
584:
585: Object propValue = getValue(propExpr, source);
586:
587: nodeAttributes.put(propName, propValue);
588: }
589:
590: node.putUserData(Attributes.class, nodeAttributes);
591: }
592:
593: /**
594: * Splits the attribute mappings in two sets, one for grouping attributes
595: * and another for non grouping (aka, multiple values) ones.
596: *
597: * @param groupByAttributeNames
598: * names of grouping attributes (input)
599: * @param allAttrMappings
600: * mappings of attributes feature (input)
601: * @param groupMappings
602: * output mappings for single attributes
603: * @param nonGroupingMappings
604: * output mappings for complex attributes
605: */
606: private final void splitMappings(final List allAttrMappings) {
607:
608: FilterAttributeExtractor attExtractor = new FilterAttributeExtractor();
609:
610: final List multivaluedAttributes = new ArrayList();
611:
612: for (Iterator itr = allAttrMappings.iterator(); itr.hasNext();) {
613: AttributeMapping attMapping = (AttributeMapping) itr.next();
614: Expression source = attMapping.getSourceExpression();
615:
616: if (attMapping.isMultiValued()) {
617: StepList targetXPath = attMapping.getTargetXPath();
618: multivaluedAttributes.add(targetXPath);
619: }
620:
621: source.accept(attExtractor, null);
622: Set sourceAttNames = new HashSet(attExtractor
623: .getAttributeNameSet());
624: // if at least one of the attributes used by the expression is not
625: // a grouping attribute, the expression addresses a multivalued
626: // target property
627: if (groupByAttributeNames.containsAll(sourceAttNames)) {
628: groupingMappings.add(attMapping);
629: } else {
630: sourceAttNames.removeAll(groupByAttributeNames);
631: GroupingFeatureIterator.LOGGER
632: .fine("attributes of multivalued property: "
633: + sourceAttNames);
634: nonGroupingMappings.add(attMapping);
635: }
636: }
637:
638: for (Iterator itr = allAttrMappings.iterator(); itr.hasNext();) {
639: AttributeMapping attMapping = (AttributeMapping) itr.next();
640: if (attMapping.isMultiValued()) {
641: continue;
642: }
643:
644: StepList targetSteps = attMapping.getTargetXPath();
645:
646: for (Iterator mvalues = multivaluedAttributes.iterator(); mvalues
647: .hasNext();) {
648: StepList parentSteps = (StepList) mvalues.next();
649:
650: if (targetSteps.size() <= parentSteps.size()) {
651: // shortcut. Couldn't be a parent path since it has
652: // less steps than child
653: continue;
654: }
655:
656: int equalCount = 0;
657: for (int i = 0; i < parentSteps.size(); i++) {
658: XPath.Step targetStep = (XPath.Step) targetSteps
659: .get(i);
660: XPath.Step parentStep = (XPath.Step) parentSteps
661: .get(i);
662: if (!targetStep.equals(parentStep)) {
663: break;
664: }
665: equalCount++;
666: }
667: int parentStepCount = parentSteps.size();
668: if (equalCount == parentStepCount) {
669: GroupingFeatureIterator.LOGGER.fine("scheduling "
670: + targetSteps
671: + " as property of multivalued attribute "
672: + parentSteps);
673: multivaluedAttributePaths.put(targetSteps,
674: parentSteps);
675: }
676: }
677: }
678: }
679:
680: private final StepList setIndexOfLastStep(final Attribute root,
681: final StepList xpathAttrDefinition, int index) {
682:
683: int insertPosition = xpathAttrDefinition.size();
684:
685: StepList indexXpath = insertIndexInXpath(root,
686: xpathAttrDefinition, index, insertPosition);
687:
688: return indexXpath;
689: }
690:
691: /**
692: *
693: * @param xpath
694: * XPath expression for which to set the <code>stepIndex</code>'th
695: * attribute to index <code>newInde</code>
696: * @param newIndex
697: * index to set for step number <code>stepIndex</code>.
698: * <code>newIndex</code> minimun value is <code>1</code>, as
699: * in XPath spec.
700: * @param stepIndex
701: * index of the step in the list of steps for <code>xpath</code>
702: * for which to set the step index to <code>newIndex</code>.
703: * The minimun value is <code>0</code>, as in Java collections
704: * and arrays.
705: * @return
706: */
707: private final StepList setIndexAtStep(StepList xpath, int newIndex,
708: int stepIndex) {
709:
710: StepList steps = (StepList) xpath.clone();
711:
712: XPath.Step step = (XPath.Step) steps.get(stepIndex);
713: step = new XPath.Step(step.getName(), newIndex);
714: steps.set(stepIndex, step);
715:
716: return steps;
717: }
718:
719: /**
720: * Insert index into step of xpath; Position indicate the step.
721: *
722: * @param featureType
723: * @param attrXpath
724: * @param index
725: * @param insertPositon
726: *
727: * @return String
728: */
729: private final StepList insertIndexInXpath(final Attribute root,
730: final StepList attrXpath, final int index,
731: final int insertPositon) {
732:
733: // Constructs an Xpath adding index in the step corresponding to complex
734: // attribute
735: StepList stepList = (StepList) attrXpath.clone();
736:
737: Step step = (Step) stepList.get(insertPositon - 1);
738: Step newStep = new XPath.Step(step.getName(), index);
739:
740: stepList.set(insertPositon - 1, newStep);
741:
742: return stepList;
743: }
744:
745: /**
746: * Extract the attributes from grouping attributes.
747: *
748: * @param Feature
749: * a source feature
750: * @return List<List<Attribute>> the the contened list has the attributes
751: * required
752: */
753: private final List/* <List<Attribute>> */extractGroupingAttributes(
754: ComplexAttribute srcFeature) {
755:
756: List/* <List<Attribute>> */attrGroup = new LinkedList/* <List<Attribute>> */();
757:
758: for (Iterator itr = this .groupByAttributeNames.iterator(); itr
759: .hasNext();) {
760: String attrName = (String) itr.next();
761: Name name = Types.typeName(attrName);
762: List/* <Attribute> */listAttrForName = srcFeature
763: .get(name);
764: attrGroup.add(listAttrForName);
765: }
766:
767: return attrGroup;
768: }
769:
770: }
|