Browse files

GEOS-5755 Support Local Resolve in App-Schema

  • Loading branch information...
1 parent 98fc74a commit e76dd59bbf06439d609a389ce98cf819d5fa14fa @NielsCharlier NielsCharlier committed May 6, 2013
View
9 modules/extension/app-schema/app-schema/pom.xml
@@ -125,7 +125,12 @@
<dependency>
<groupId>xpp3</groupId>
<artifactId>xpp3_min</artifactId>
- </dependency>
+ </dependency>
+ <dependency>
+ <groupId>org.geotools.ogc</groupId>
+ <artifactId>net.opengis.wfs</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<!-- for FilenameUtils -->
<groupId>commons-io</groupId>
@@ -186,7 +191,7 @@
<artifactId>geosciml-3.0-seegrid</artifactId>
<version>3.0.0-1</version>
<scope>test</scope>
- </dependency>
+ </dependency>
</dependencies>
View
187 ...ma/app-schema/src/main/java/org/geotools/data/complex/AbstractMappingFeatureIterator.java
@@ -19,25 +19,33 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
+
+import net.opengis.wfs20.ResolveValueType;
+
import org.geotools.data.DataSourceException;
import org.geotools.data.Query;
import org.geotools.data.complex.filter.XPath;
import org.geotools.data.complex.filter.XPathUtil.StepList;
import org.geotools.factory.CommonFactoryFinder;
+import org.geotools.factory.Hints;
import org.geotools.feature.AppSchemaFeatureFactoryImpl;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.Types;
import org.geotools.feature.type.ComplexFeatureTypeFactoryImpl;
import org.geotools.filter.FilterFactoryImplNamespaceAware;
+import org.geotools.filter.identity.FeatureIdImpl;
import org.geotools.xlink.XLINK;
import org.opengis.feature.Attribute;
import org.opengis.feature.Feature;
import org.opengis.feature.FeatureFactory;
import org.opengis.feature.type.AttributeDescriptor;
+import org.opengis.feature.type.AttributeType;
import org.opengis.feature.type.FeatureTypeFactory;
import org.opengis.feature.type.PropertyDescriptor;
import org.opengis.feature.GeometryAttribute;
@@ -47,9 +55,11 @@
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.PropertyName;
+import org.opengis.filter.identity.FeatureId;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.NamespaceSupport;
+
import com.vividsolutions.jts.geom.EmptyGeometry;
import com.vividsolutions.jts.geom.Geometry;
@@ -114,6 +124,10 @@
protected int featureCounter;
protected NamespaceSupport namespaces;
+
+ protected int resolveDepth;
+
+ protected Integer resolveTimeOut;
/**
* True if hasNext has been called prior to calling next()
@@ -160,6 +174,19 @@ public AbstractMappingFeatureIterator(AppSchemaDataAccess store, FeatureTypeMapp
xpathAttributeBuilder.setFeatureFactory(attf);
initialiseSourceFeatures(mapping, unrolledQuery, query.getCoordinateSystemReproject());
xpathAttributeBuilder.setFilterFactory(namespaceAwareFilterFactory);
+
+ Hints hints = query.getHints();
+ ResolveValueType resolveVal = (ResolveValueType) hints.get( Hints.RESOLVE );
+ boolean resolve = ResolveValueType.ALL.equals(resolveVal) || ResolveValueType.LOCAL.equals(resolveVal);
+
+ if (!resolve && !ResolveValueType.NONE.equals(resolveVal)) {
+ throw new IllegalArgumentException("Resolve:" + resolveVal.getName() + " is not supported in app-schema!");
+ }
+
+ Integer atd = (Integer) hints.get(Hints.ASSOCIATION_TRAVERSAL_DEPTH);
+
+ resolveDepth = resolve ? atd==null? 0 : atd : 0;
+ resolveTimeOut = (Integer) hints.get( Hints.RESOLVE_TIMEOUT );
}
//properties can only be set by constructor, before initialising source features
@@ -302,50 +329,162 @@ protected Map getClientProperties(Property attribute) throws DataSourceException
return clientProperties;
}
- protected void setClientProperties(final Attribute target, final Object source,
- final Map<Name, Expression> clientProperties) {
+ private class FeatureFinder implements Runnable {
+ private Feature feature = null;
+ private String refId;
+ private Hints hints;
+ public AtomicBoolean stopFlag = new AtomicBoolean(false);
+
+ public synchronized Feature getFeature() {
+ return feature;
+ }
+
+ private synchronized void setFeature (Feature feature) {
+ this.feature = feature;
+ }
+
+ public FeatureFinder (String refId, Hints hints) {
+ this.refId = refId;
+ this.hints = hints;
+ }
+
+ @Override
+ public void run() {
+ try {
+ Feature feature = DataAccessRegistry.getInstance().findFeature(new FeatureIdImpl (refId), hints, stopFlag);
+ if (!stopFlag.get()) {
+ setFeature(feature);
+ }
+ } catch (IOException e) { // ignore, no resolve
+ }
+ }
+ };
+
+
+ protected static String referenceToIdentifier(String reference) {
+
+ //TODO: support custom rules in mapping file
+
+ String[] urn = reference.split(":");
+
+ String lastPart = urn[urn.length - 1];
+
+ if (lastPart.contains("#")) {
+ lastPart = lastPart.substring(lastPart.lastIndexOf("#"));
+ }
+
+ if ("missing".equals(urn[urn.length - 1]) || "unknown".equals(urn[urn.length - 1])) {
+ return null;
+ }
+
+ return lastPart;
+ }
+
+ protected Attribute setAttributeContent(Attribute target, StepList xpath, Object value, String id, AttributeType targetNodeType, boolean isXlinkRef, Expression sourceExpression, Object source, final Map<Name, Expression> clientProperties, boolean ignoreXlinkHref){
+ Attribute instance = null;
+
+ Map<Name, Expression> properties = new HashMap<Name, Expression>(clientProperties);
+
+ if (ignoreXlinkHref) {
+ properties.remove(XLINK_HREF_NAME);
+ }
+
+ if (properties.containsKey(XLINK_HREF_NAME) && resolveDepth > 0) {
+ // local resolve
+
+ String refid = referenceToIdentifier(getValue(properties.get(XLINK_HREF_NAME), source).toString());
+
+ if (refid != null) {
+
+ final Hints hints = new Hints();
+ if (resolveDepth > 1) {
+ hints.put(Hints.RESOLVE, ResolveValueType.ALL);
+ hints.put(Hints.RESOLVE_TIMEOUT, resolveTimeOut);
+ hints.put(Hints.ASSOCIATION_TRAVERSAL_DEPTH, resolveDepth - 1);
+ } else {
+ hints.put(Hints.RESOLVE, ResolveValueType.NONE);
+ }
+
+ // let's try finding it
+ FeatureFinder finder = new FeatureFinder(refid, hints);
+ Thread thread = new Thread(finder);
+ long currentTime = System.currentTimeMillis();
+ thread.start();
+ while (thread.isAlive()
+ && (System.currentTimeMillis() - currentTime) / 1000 < resolveTimeOut) {
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException t) {
+ }
+ }
+ synchronized (finder.stopFlag) {
+ finder.stopFlag.set(true);
+ }
+
+ if (finder.getFeature() != null) {
+ // found it
+
+ instance = xpathAttributeBuilder.set(target, xpath,
+ Collections.singletonList(finder.getFeature()), id, targetNodeType,
+ false, sourceExpression);
+ properties.remove(XLINK_HREF_NAME);
+ }
+ }
+
+ }
+
+ if (instance == null) {
+ instance = xpathAttributeBuilder.set(target, xpath, value, id, targetNodeType, false, sourceExpression);
+ }
+
+ setClientProperties(instance, source, properties);
+
+ return instance;
+ }
+
+ protected void setClientProperties(final Attribute target, final Object source, final Map<Name, Expression> clientProperties) {
if (target == null) {
return;
}
if (source == null && clientProperties.isEmpty()) {
return;
}
-
+
// NC - first calculate target attributes
final Map<Name, Object> targetAttributes = new HashMap<Name, Object>();
if (target.getUserData().containsValue(Attributes.class)) {
targetAttributes.putAll((Map<? extends Name, ? extends Object>) target.getUserData()
.get(Attributes.class));
}
- for (Map.Entry<Name, Expression> entry : clientProperties.entrySet()) {
- Name propName = entry.getKey();
- Object propExpr = entry.getValue();
- Object propValue;
- if (propExpr instanceof Expression) {
- propValue = getValue((Expression) propExpr, source);
- } else {
- propValue = propExpr;
- }
- if (propValue != null) {
- if (propValue instanceof Collection) {
- if (!((Collection)propValue).isEmpty()) {
- propValue = ((Collection)propValue).iterator().next();
- targetAttributes.put(propName, propValue);
- }
- } else {
- targetAttributes.put(propName, propValue);
- }
- }
- }
+ for (Map.Entry<Name, Expression> entry : clientProperties.entrySet()) {
+ Name propName = entry.getKey();
+ Object propExpr = entry.getValue();
+ Object propValue;
+ if (propExpr instanceof Expression) {
+ propValue = getValue((Expression) propExpr, source);
+ } else {
+ propValue = propExpr;
+ }
+ if (propValue != null) {
+ if (propValue instanceof Collection) {
+ if (!((Collection) propValue).isEmpty()) {
+ propValue = ((Collection) propValue).iterator().next();
+ targetAttributes.put(propName, propValue);
+ }
+ } else {
+ targetAttributes.put(propName, propValue);
+ }
+ }
+ }
// FIXME should set a child Property.. but be careful for things that
// are smuggled in there internally and don't exist in the schema, like
// XSDTypeDefinition, CRS etc.
if (targetAttributes.size() > 0) {
target.getUserData().put(Attributes.class, targetAttributes);
}
- setGeometryUserData(target, targetAttributes);
+ setGeometryUserData(target, targetAttributes);
}
protected void setGeometryUserData(Attribute target, Map<Name, Object> targetAttributes) {
View
29 ...on/app-schema/app-schema/src/main/java/org/geotools/data/complex/AppSchemaDataAccess.java
@@ -26,7 +26,9 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import org.geotools.data.DataAccess;
@@ -43,6 +45,9 @@
import org.geotools.data.complex.filter.XPathUtil.StepList;
import org.geotools.data.joining.JoiningQuery;
import org.geotools.factory.CommonFactoryFinder;
+import org.geotools.factory.Hints;
+import org.geotools.feature.FeatureCollection;
+import org.geotools.feature.FeatureIterator;
import org.geotools.feature.Types;
import org.geotools.filter.FilterAttributeExtractor;
import org.geotools.filter.SortByImpl;
@@ -57,6 +62,7 @@
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.PropertyName;
+import org.opengis.filter.identity.FeatureId;
import org.opengis.filter.sort.SortBy;
import org.opengis.filter.sort.SortOrder;
@@ -640,4 +646,27 @@ public void updateSchema(Name typeName, FeatureType featureType) throws IOExcept
throws IOException {
return new MappingFeatureSource(this, getMappingByName(typeName));
}
+
+ public Feature findFeature(FeatureId id, Hints hints, AtomicBoolean stopFlag) throws IOException {
+ Feature result = null;
+ for (Entry<Name, FeatureTypeMapping> mapping: mappings.entrySet()) {
+ Filter filter = filterFac.id(id);
+ FeatureCollection<FeatureType, Feature> fCollection = new MappingFeatureSource(this, mapping.getValue()).getFeatures(filter, hints);
+ FeatureIterator<Feature> iterator = fCollection.features();
+ if (iterator.hasNext()) {
+ result = iterator.next();
+ }
+ iterator.close();
+ if (result != null){
+ return result;
+ }
+
+ synchronized(stopFlag) {
+ if (stopFlag.get()) {
+ return null;
+ }
+ }
+ }
+ return null;
+ }
}
View
22 .../app-schema/src/main/java/org/geotools/data/complex/DataAccessMappingFeatureIterator.java
@@ -521,6 +521,14 @@ protected Attribute setAttributeValue(Attribute target, String id, final Object
values = getValues(attMapping.isMultiValued(), sourceExpression, source);
}
boolean isHRefLink = isByReference(clientPropsMappings, isNestedFeature);
+ int newResolveDepth = resolveDepth;
+ //if resolving, no xlink:href for chained feature
+ boolean ignoreXlinkHref = false;
+ if (isHRefLink && newResolveDepth > 0) {
+ isHRefLink = false;
+ newResolveDepth--;
+ ignoreXlinkHref = true;
+ }
if (isNestedFeature) {
if (values == null) {
// polymorphism use case, if the value doesn't match anything, don't encode
@@ -549,7 +557,7 @@ protected Attribute setAttributeValue(Attribute target, String id, final Object
.getInputFeatures(this, val, getIdValues(source), source, reprojection, selectedProperties, includeMandatory));
} else {
nestedFeatures.addAll(((NestedAttributeMapping) attMapping).getFeatures(
- this, val, getIdValues(source), reprojection, source, selectedProperties, includeMandatory));
+ this, val, getIdValues(source), reprojection, source, selectedProperties, includeMandatory, newResolveDepth, resolveTimeOut));
}
}
values = nestedFeatures;
@@ -561,7 +569,7 @@ protected Attribute setAttributeValue(Attribute target, String id, final Object
values = ((NestedAttributeMapping) attMapping).getInputFeatures(this, values, getIdValues(source), source, reprojection, selectedProperties, includeMandatory);
} else {
values = ((NestedAttributeMapping) attMapping).getFeatures(this, values, getIdValues(source), reprojection,
- source, selectedProperties, includeMandatory);
+ source, selectedProperties, includeMandatory, newResolveDepth, resolveTimeOut);
}
if (isHRefLink) {
// only need to set the href link value, not the nested feature properties
@@ -597,9 +605,7 @@ protected Attribute setAttributeValue(Attribute target, String id, final Object
} else {
valueList.add(singleVal);
}
- instance = xpathAttributeBuilder.set(target, xpath, valueList, id,
- targetNodeType, false, sourceExpression);
- setClientProperties(instance, source, clientPropsMappings);
+ instance = setAttributeContent(target, xpath, valueList, id, targetNodeType, false, sourceExpression, source, clientPropsMappings, ignoreXlinkHref);
}
} else {
if (values instanceof Attribute) {
@@ -612,9 +618,7 @@ protected Attribute setAttributeValue(Attribute target, String id, final Object
}
values = ((Attribute) values).getValue();
}
- instance = xpathAttributeBuilder.set(target, xpath, values, id,
- targetNodeType, false, sourceExpression);
- setClientProperties(instance, source, clientPropsMappings);
+ instance = setAttributeContent(target, xpath, values, id, targetNodeType, false, sourceExpression, source, clientPropsMappings, ignoreXlinkHref);
}
if (instance != null && attMapping.encodeIfEmpty()) {
@@ -981,7 +985,7 @@ protected Feature computeNext() throws IOException {
false, sourceExpr);
} else {
// simple attributes
- instance.setValue(valueString);
+ instance.setValue(valueString);
}
}
} else if (attMapping.isMultiValued()) {
View
22 ...ion/app-schema/app-schema/src/main/java/org/geotools/data/complex/DataAccessRegistry.java
@@ -22,16 +22,19 @@
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
import org.geotools.data.DataAccess;
import org.geotools.data.DataSourceException;
import org.geotools.data.DataStore;
import org.geotools.data.FeatureSource;
import org.geotools.data.Repository;
+import org.geotools.factory.Hints;
import org.geotools.util.InterpolationProperties;
import org.opengis.feature.Feature;
import org.opengis.feature.type.FeatureType;
import org.opengis.feature.type.Name;
+import org.opengis.filter.identity.FeatureId;
/**
* A registry that stores data access instances per application. This allows feature sources from
@@ -360,6 +363,25 @@ protected void throwDataSourceException(Name featureTypeName) throws IOException
+ " Has the data access been registered in DataAccessRegistry?" + " Available: "
+ typeNames.toString());
}
+
+
+ public Feature findFeature(FeatureId id, Hints hints, AtomicBoolean stopFlag) throws IOException {
+ for (DataAccess<FeatureType, Feature> dataAccess : registry) {
+ if (dataAccess instanceof AppSchemaDataAccess) {
+ Feature feature = ((AppSchemaDataAccess) dataAccess).findFeature(id, hints, stopFlag);
+ if (feature != null) {
+ return feature;
+ }
+ synchronized(stopFlag) {
+ if (stopFlag.get()) {
+ return null;
+ }
+ }
+ }
+ }
+ return null;
+
+ }
}
View
18 ...n/app-schema/app-schema/src/main/java/org/geotools/data/complex/MappingFeatureSource.java
@@ -31,6 +31,7 @@
import org.geotools.data.QueryCapabilities;
import org.geotools.data.ResourceInfo;
import org.geotools.data.joining.JoiningQuery;
+import org.geotools.factory.Hints;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.geometry.jts.ReferencedEnvelope;
@@ -84,8 +85,16 @@ public ReferencedEnvelope getBounds() throws IOException {
private Query namedQuery(Filter filter, int countLimit) {
return namedQuery(filter, countLimit, false);
}
-
+
+ private Query namedQuery(Filter filter, int countLimit, Hints hints) {
+ return namedQuery(filter, countLimit, false, hints);
+ }
+
private Query namedQuery(Filter filter, int countLimit, boolean isJoining) {
+ return namedQuery(filter, countLimit, isJoining, null);
+ }
+
+ private Query namedQuery(Filter filter, int countLimit, boolean isJoining, Hints hints) {
Query query = isJoining ? new JoiningQuery() : new Query();
if (getName().getNamespaceURI() != null) {
try {
@@ -97,8 +106,9 @@ private Query namedQuery(Filter filter, int countLimit, boolean isJoining) {
query.setTypeName(getName().getLocalPart());
query.setFilter(filter);
query.setMaxFeatures(countLimit);
+ query.setHints(hints);
return query;
- }
+ }
private Query namedQuery(Query query) {
Query namedQuery = namedQuery(query.getFilter(), query.getMaxFeatures(), query instanceof JoiningQuery);
@@ -168,6 +178,10 @@ public FeatureTypeMapping getMapping() {
public FeatureCollection<FeatureType, Feature> getFeatures(Filter filter) throws IOException {
return new MappingFeatureCollection(store, mapping, namedQuery(filter, Integer.MAX_VALUE));
}
+
+ public FeatureCollection<FeatureType, Feature> getFeatures(Filter filter, Hints hints) throws IOException {
+ return new MappingFeatureCollection(store, mapping, namedQuery(filter, Integer.MAX_VALUE, hints));
+ }
public FeatureCollection<FeatureType, Feature> getFeatures() throws IOException {
return new MappingFeatureCollection(store, mapping, namedQuery(Filter.INCLUDE,
View
63 ...app-schema/app-schema/src/main/java/org/geotools/data/complex/NestedAttributeMapping.java
@@ -25,6 +25,8 @@
import java.util.Map;
import java.util.logging.Logger;
+import net.opengis.wfs20.ResolveValueType;
+
import org.geotools.data.FeatureSource;
import org.geotools.data.Query;
import org.geotools.data.complex.filter.XPathUtil.StepList;
@@ -106,7 +108,7 @@
* true if the type is depending on a function value, i.e. could be a Function
*/
private boolean isConditional;
-
+
/**
* Sole constructor
*
@@ -187,21 +189,36 @@ public boolean isNestedAttribute() {
return Collections.EMPTY_LIST;
}
- // find source expression on nested features side
- List<AttributeMapping> mappings = featureTypeMapping
- .getAttributeMappingsIgnoreIndex(this.nestedTargetXPath);
- if (mappings.size() < 1) {
- throw new IllegalArgumentException("Mapping is missing for: '"
- + this.nestedTargetXPath + "'!");
- }
- AttributeMapping mapping = mappings.get(0);
- nestedSourceExpression = mapping.getSourceExpression();
+ AttributeMapping mapping = getMapping(featureTypeMapping);
+ nestedSourceExpression = mapping.getSourceExpression();
isMultiple = mapping.isMultiValued();
}
return getFilteredFeatures(foreignKeyValue, isMultiple);
}
+ public AttributeMapping getMapping(FeatureTypeMapping featureTypeMapping) {
+ // find source expression on nested features side
+ AttributeMapping mapping;
+ if (!ComplexFeatureConstants.FEATURE_CHAINING_LINK_STRING.equals(nestedTargetXPath.get(nestedTargetXPath.size()-1).getName().getLocalPart())) {
+ List<AttributeMapping> mappings = featureTypeMapping
+ .getAttributeMappingsIgnoreIndex(this.nestedTargetXPath);
+ if (mappings.size() < 1) {
+ throw new IllegalArgumentException("Mapping is missing for: '"
+ + this.nestedTargetXPath + "'!");
+ }
+ mapping = mappings.get(0);
+ }
+ else {
+ mapping = featureTypeMapping.getAttributeMapping(this.nestedTargetXPath);
+ if (mapping == null) {
+ throw new IllegalArgumentException("Mapping is missing for: '"
+ + this.nestedTargetXPath + "'!");
+ }
+ }
+ return mapping;
+ }
+
/**
* Run the query to get built features from a table based on a foreign key.
*
@@ -221,6 +238,7 @@ public boolean isNestedAttribute() {
Filter filter = filterFac.equals(this.nestedSourceExpression, filterFac
.literal(foreignKeyValue));
+
// get all the nested features based on the link values
FeatureCollection<FeatureType, Feature> fCollection = source.getFeatures(filter);
FeatureIterator<Feature> it = fCollection.features();
@@ -308,14 +326,8 @@ public boolean isNestedAttribute() {
nestedIdExpression = fMapping.getFeatureIdExpression();
- // find source expression on nested features side
- List<AttributeMapping> mappings = fMapping
- .getAttributeMappingsIgnoreIndex(this.nestedTargetXPath);
- if (mappings.size() < 1) {
- throw new IllegalArgumentException("Mapping is missing for: '"
- + this.nestedTargetXPath + "'!");
- }
- AttributeMapping mapping = mappings.get(0);
+ // find source expression on nested features side
+ AttributeMapping mapping = getMapping(fMapping);
nestedSourceExpression = mapping.getSourceExpression();
isMultiple = mapping.isMultiValued();
}
@@ -338,8 +350,8 @@ public boolean isNestedAttribute() {
* @throws IOException
*/
public List<Feature> getFeatures(Object foreignKeyValue,
- CoordinateReferenceSystem reprojection, Feature feature) throws IOException{
- return getFeatures(null, foreignKeyValue, null, reprojection, feature, null, true);
+ CoordinateReferenceSystem reprojection, Feature feature, int resolveDepth, Integer resolveTimeOut) throws IOException{
+ return getFeatures(null, foreignKeyValue, null, reprojection, feature, null, true, resolveDepth, resolveTimeOut);
}
@@ -354,7 +366,7 @@ public boolean isNestedAttribute() {
* @throws IOException
*/
public List<Feature> getFeatures(Object source, Object foreignKeyValue, List<Object> idValues,
- CoordinateReferenceSystem reprojection, Object feature, List<PropertyName> selectedProperties, boolean includeMandatory) throws IOException {
+ CoordinateReferenceSystem reprojection, Object feature, List<PropertyName> selectedProperties, boolean includeMandatory, int resolveDepth, Integer resolveTimeOut) throws IOException {
if (foreignKeyValue == null) {
return Collections.<Feature>emptyList();
@@ -387,6 +399,15 @@ public boolean isNestedAttribute() {
final Hints hints = new Hints();
hints.put(Query.INCLUDE_MANDATORY_PROPS, includeMandatory);
+
+ if (resolveDepth > 0 ) {
+ hints.put(Hints.RESOLVE, ResolveValueType.ALL);
+ hints.put(Hints.ASSOCIATION_TRAVERSAL_DEPTH, resolveDepth);
+ hints.put(Hints.RESOLVE_TIMEOUT, resolveTimeOut);
+ } else {
+ hints.put(Hints.RESOLVE, ResolveValueType.NONE);
+ }
+
query.setHints(hints);
query.setProperties(selectedProperties);
View
20 ...ema/app-schema/src/main/java/org/geotools/data/joining/JoiningNestedAttributeMapping.java
@@ -22,6 +22,8 @@
import java.util.List;
import java.util.Map;
+import net.opengis.wfs20.ResolveValueType;
+
import org.geotools.data.FeatureSource;
import org.geotools.data.Query;
import org.geotools.data.complex.AppSchemaDataAccessRegistry;
@@ -127,7 +129,7 @@ public JoiningNestedAttributeMapping(Expression idExpression, Expression parentE
*/
public DataAccessMappingFeatureIterator initSourceFeatures(Instance instance,
Name featureTypeName, CoordinateReferenceSystem reprojection,
- List<PropertyName> selectedProperties, boolean includeMandatory) throws IOException {
+ List<PropertyName> selectedProperties, boolean includeMandatory, int resolveDepth, Integer resolveTimeOut) throws IOException {
JoiningQuery query = new JoiningQuery();
query.setCoordinateSystemReproject(reprojection);
@@ -169,6 +171,16 @@ public DataAccessMappingFeatureIterator initSourceFeatures(Instance instance,
final Hints hints = new Hints();
hints.put(Query.INCLUDE_MANDATORY_PROPS, includeMandatory);
+
+ if (resolveDepth > 0 ) {
+ hints.put(Hints.RESOLVE, ResolveValueType.ALL);
+ hints.put(Hints.ASSOCIATION_TRAVERSAL_DEPTH, resolveDepth);
+ hints.put(Hints.RESOLVE_TIMEOUT, resolveTimeOut);
+ } else {
+ hints.put(Hints.RESOLVE, ResolveValueType.NONE);
+ }
+
+
query.setHints(hints);
query.setProperties(selectedProperties);
@@ -299,7 +311,7 @@ public void close(Object caller) {
.get((Name) featureTypeName);
if (featureIterator == null) {
featureIterator = initSourceFeatures(instance, (Name) featureTypeName, reprojection,
- selectedProperties, includeMandatory);
+ selectedProperties, includeMandatory, 0, null);
}
Expression nestedSourceExpression = instance.nestedSourceExpressions
.get((Name) featureTypeName);
@@ -347,7 +359,7 @@ public void close(Object caller) {
@Override
public List<Feature> getFeatures(Object caller, Object foreignKeyValue, List<Object> idValues,
CoordinateReferenceSystem reprojection, Object feature,
- List<PropertyName> selectedProperties, boolean includeMandatory) throws IOException {
+ List<PropertyName> selectedProperties, boolean includeMandatory, int resolveDepth, Integer resolveTimeOut) throws IOException {
if (isSameSource()) {
// if linkField is null, this method shouldn't be called because the mapping
@@ -370,7 +382,7 @@ public void close(Object caller) {
.get((Name) featureTypeName);
if (featureIterator == null) {
featureIterator = initSourceFeatures(instance, (Name) featureTypeName, reprojection,
- selectedProperties, includeMandatory);
+ selectedProperties, includeMandatory, resolveDepth, resolveTimeOut);
}
Expression nestedSourceExpression = instance.nestedSourceExpressions
.get((Name) featureTypeName);
View
2 ...on/app-schema/app-schema/src/main/java/org/geotools/filter/NestedAttributeExpression.java
@@ -275,7 +275,7 @@ private Step getLastStep() {
return nestedMapping.getInputFeatures(val, fMapping);
} else {
// app-schema with a complex feature source
- return nestedMapping.getFeatures(val, null, root);
+ return nestedMapping.getFeatures(val, null, root, 0, null);
}
}
View
14 modules/library/metadata/src/main/java/org/geotools/factory/Hints.java
@@ -813,6 +813,20 @@
//////// Data stores ////////
//////// ////////
////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Resolve setting for resolving resources. ("local", "none", "remote" or "all")
+ * <p>
+ * This maps directly to the {@code resolve} parameter in a WFS query.
+ */
+ public static final Key RESOLVE = new Key("net.opengis.wfs20.ResolveValueType");
+
+ /**
+ * The maximum time-out for resolving resources.
+ * <p>
+ * This maps directly to the {@code resolveTimeOut} parameter in a WFS query.
+ */
+ public static final Hints.Key RESOLVE_TIMEOUT = new Key(Integer.class);
/**
* The maximum number of associations traversed in a datastore query.

0 comments on commit e76dd59

Please sign in to comment.