001: /*
002: * GeoTools - 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: package org.geotools.data.complex;
018:
019: import java.io.IOException;
020: import java.util.Iterator;
021: import java.util.List;
022: import java.util.logging.Logger;
023:
024: import javax.xml.namespace.QName;
025:
026: import org.geotools.data.Query;
027: import org.geotools.data.Source;
028: import org.geotools.data.complex.filter.XPath.Step;
029: import org.geotools.data.complex.filter.XPath.StepList;
030: import org.geotools.data.feature.FeatureSource2;
031: import org.geotools.factory.CommonFactoryFinder;
032: import org.geotools.feature.iso.AttributeFactoryImpl;
033: import org.geotools.feature.iso.Types;
034: import org.opengis.feature.Attribute;
035: import org.opengis.feature.ComplexAttribute;
036: import org.opengis.feature.FeatureCollection;
037: import org.opengis.feature.FeatureFactory;
038: import org.opengis.feature.type.Name;
039: import org.opengis.filter.Filter;
040: import org.opengis.filter.FilterFactory;
041: import org.opengis.filter.expression.Expression;
042:
043: /**
044: * Base class for mapping iterator strategies.
045: * <p>
046: * This class provides the common behavior for iterating over a mapped
047: * FeatureSource and returning instances of the target FeatureType, by unpacking
048: * the incoming <code>org.geotools.data.Query</code> and creating its
049: * equivalent over the mapped FeatureType.
050: * </p>
051: * <p>
052: * This way, subclasses should only worry on implementing <code>next()</code>
053: * and <code>hasNext()</code> in a way according to their fetching stratagy,
054: * while this superclass provides them with a FeatureIterator already made by
055: * executing the unpacked Query over the source FeatureSource.
056: * </p>
057: *
058: * @author Gabriel Roldan, Axios Engineering
059: * @version $Id: AbstractMappingFeatureIterator.java 27862 2007-11-12 19:51:19Z desruisseaux $
060: * @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/AbstractMappingFeatureIterator.java $
061: * @since 2.4
062: */
063: abstract class AbstractMappingFeatureIterator implements Iterator/* <Feature> */{
064:
065: private static final Logger LOGGER = org.geotools.util.logging.Logging
066: .getLogger(AbstractMappingFeatureIterator.class
067: .getPackage().getName());
068:
069: /**
070: * The mappings for the source and target schemas
071: */
072: protected FeatureTypeMapping mapping;
073:
074: /**
075: * Expression to evaluate the feature id
076: */
077: protected Expression featureFidMapping;
078:
079: /**
080: * Factory used to create the target feature and attributes
081: */
082: protected FeatureFactory attf;
083:
084: protected FeatureCollection features;
085:
086: protected Iterator sourceFeatures;
087:
088: protected ComplexDataStore store;
089:
090: protected Source featureSource;
091:
092: /**
093: *
094: * @param store
095: * @param mapping
096: * place holder for the target type, the surrogate FeatureSource
097: * and the mappings between them.
098: * @param query
099: * the query over the target feature type, that is to be unpacked
100: * to its equivalent over the surrogate feature type.
101: * @throws IOException
102: */
103: public AbstractMappingFeatureIterator(ComplexDataStore store,
104: FeatureTypeMapping mapping, Query query) throws IOException {
105: this .store = store;
106: this .attf = new AttributeFactoryImpl();
107: Name name = mapping.getTargetFeature().getName();
108: this .featureSource = store.access(name);
109:
110: List attributeMappings = mapping.getAttributeMappings();
111:
112: for (Iterator it = attributeMappings.iterator(); it.hasNext();) {
113: AttributeMapping attMapping = (AttributeMapping) it.next();
114: StepList targetXPath = attMapping.getTargetXPath();
115: if (targetXPath.size() > 1) {
116: continue;
117: }
118: Step step = (Step) targetXPath.get(0);
119: QName stepName = step.getName();
120: if (Types.equals(name, stepName)) {
121: featureFidMapping = attMapping
122: .getIdentifierExpression();
123: break;
124: }
125: }
126:
127: this .mapping = mapping;
128:
129: if (featureFidMapping == null
130: || Expression.NIL.equals(featureFidMapping)) {
131: FilterFactory ff = CommonFactoryFinder
132: .getFilterFactory(null);
133: featureFidMapping = ff.property("@id");
134: }
135:
136: Query unrolledQuery = getUnrolledQuery(query);
137: Filter filter = unrolledQuery.getFilter();
138:
139: FeatureSource2 mappedSource = mapping.getSource();
140:
141: features = (FeatureCollection) mappedSource.content(filter);
142:
143: this .sourceFeatures = features.iterator();
144: }
145:
146: /**
147: * Subclasses must override to provide a query appropiate to its underlying
148: * feature source.
149: *
150: * @param query
151: * the original query against the output schema
152: * @return a query appropiate to be executed over the underlying feature
153: * source.
154: */
155: protected abstract Query getUnrolledQuery(Query query);
156:
157: /**
158: * Shall not be called, just throws an UnsupportedOperationException
159: */
160: public void remove() {
161: throw new UnsupportedOperationException();
162: }
163:
164: /**
165: * Closes the underlying FeatureIterator
166: */
167: public void close() {
168: if (features != null && sourceFeatures != null) {
169: features.close(sourceFeatures);
170: sourceFeatures = null;
171: features = null;
172: }
173: }
174:
175: /**
176: * Based on the set of xpath expression/id extracting expression, finds the
177: * ID for the attribute <code>attributeXPath</code> from the source
178: * complex attribute.
179: *
180: * @param attributeXPath
181: * the location path of the attribute to be created, for which to
182: * obtain the id by evaluating the corresponding
183: * <code>org.geotools.filter.Expression</code> from
184: * <code>sourceInstance</code>.
185: * @param sourceInstance
186: * a complex attribute which is the source of the mapping.
187: * @return the ID to be applied to a new attribute instance addressed by
188: * <code>attributeXPath</code>, or <code>null</code> if there
189: * is no an id mapping for that attribute.
190: */
191: protected String extractIdForAttribute(
192: final Expression idExpression,
193: ComplexAttribute sourceInstance) {
194: String value = (String) idExpression.evaluate(sourceInstance,
195: String.class);
196: return value;
197: }
198:
199: protected String extractIdForFeature(ComplexAttribute sourceInstance) {
200: String fid = (String) featureFidMapping.evaluate(
201: sourceInstance, String.class);
202: return fid;
203: }
204:
205: protected Object getValue(Expression expression,
206: Object sourceFeature) {
207: Object value;
208: value = expression.evaluate(sourceFeature);
209: if (value instanceof Attribute) {
210: value = ((Attribute) value).getValue();
211: }
212: return value;
213: }
214: }
|