
org.geotools.feature.ComplexFeatureBuilder Maven / Gradle / Ivy
/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2012, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.feature;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.geotools.factory.CommonFactoryFinder;
import org.opengis.feature.Feature;
import org.opengis.feature.FeatureFactory;
import org.opengis.feature.Property;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.FeatureType;
import org.opengis.feature.type.Name;
import org.opengis.feature.type.PropertyDescriptor;
/**
* The complex feature builder allows the construction of features by progressively appending their
* components and deferring the construction till you're ready.
*
* @author Adam Brown (Curtin University of Technology)
*/
public class ComplexFeatureBuilder extends FeatureBuilder {
Map> values = new HashMap>();
AttributeDescriptor ad = null;
public ComplexFeatureBuilder(FeatureType featureType) {
this(featureType, CommonFactoryFinder.getFeatureFactory(null));
}
protected ComplexFeatureBuilder(FeatureType featureType, FeatureFactory factory) {
super(featureType, factory);
}
public ComplexFeatureBuilder(AttributeDescriptor ad) {
this(ad, CommonFactoryFinder.getFeatureFactory(null));
}
protected ComplexFeatureBuilder(AttributeDescriptor ad, FeatureFactory factory) {
super((FeatureType) ad.getType(), factory);
this.ad = ad;
}
/**
* Build and return the feature you've been constructing. If the id is null it will be assigned
* from FeatureBuilder.createDefaultFeatureId().
*/
@Override
public Feature buildFeature(String id) {
// Instantiate if null:
id = id == null ? FeatureBuilder.createDefaultFeatureId() : id;
// Validate the values against the featureType; we need to make sure
// that requirements are honoured:
for (PropertyDescriptor propertyDescriptor : super.featureType.getDescriptors()) {
Name name = propertyDescriptor.getName();
// Create a List of Properties for this name if we don't already
// have one:
if (!values.containsKey(name)) {
values.put(name, new ArrayList());
}
// Get the List of Properties:
List properties = values.get(name);
// See if there's a mismatch between the number of properties and
// minOccurs value:
int minOccurs = propertyDescriptor.getMinOccurs();
int numberOfProperties = properties.size();
if (numberOfProperties < minOccurs) {
// If the value is nillable anyway then just default it to null:
if (propertyDescriptor.isNillable()
&& AttributeDescriptor.class.isAssignableFrom(
propertyDescriptor.getClass())) {
do {
Property nullProperty =
new AttributeImpl(
propertyDescriptor.getType().getBinding().cast(null),
(AttributeDescriptor) propertyDescriptor,
null);
properties.add(nullProperty);
} while (++numberOfProperties < minOccurs);
}
// NOTE: I was wondering if you could have another if-else here
// to try to apply default values if they're set..
// it seems like a good idea but the only problem is that
// they're only present on the AttributeDescriptors...
else {
throw new IllegalStateException(
String.format(
"Failed to build feature '%s'; its property '%s' requires at least %s occurrence(s) but number of occurrences was %s.",
featureType.getName(), name, minOccurs, numberOfProperties));
}
}
}
// Merge the Map> into one collection of
// properties:
Collection properties = new ArrayList();
for (Name key : values.keySet()) {
properties.addAll(values.get(key));
}
this.values.clear();
if (ad != null) {
return factory.createFeature(properties, ad, id);
} else {
return factory.createFeature(properties, featureType, id);
}
}
/**
* Append a property value to the complex feature under construction and associate it with the
* name specified.
*
* @param name The name of the property you wish to set.
* @param value The value of the property to append.
*/
public void append(Name name, Property value) {
PropertyDescriptor propertyDescriptor = featureType.getDescriptor(name);
// The 'name' must exist in the type, if not, throw an exception:
if (propertyDescriptor == null) {
throw new IllegalArgumentException(
String.format(
"The name '%s' is not a valid descriptor name for the type '%s'.",
name, this.featureType.getName()));
}
Class> expectedClass = propertyDescriptor.getType().getBinding();
if (value != null) {
Class> providedClass = value.getType().getBinding();
// Make sure that the provided class and the expected class match or
// that the expectedClass is a base class of the providedClass:
if (!providedClass.equals(expectedClass)
&& !expectedClass.isAssignableFrom(providedClass)) {
throw new IllegalArgumentException(
String.format(
"The value provided contains an object of '%s' but the method expects an object of '%s'.",
providedClass, expectedClass));
}
} else { // value == null
if (propertyDescriptor.isNillable()) {
value = (Property) expectedClass.cast(null);
} else {
// NOTE: This could possibly to changed to allow for processing
// remote xlinks.
value = (Property) expectedClass.cast(null);
}
}
// At this point the converted value has been set so we must persist it
// to the object's state:
ArrayList valueList;
if (values.containsKey(name)) {
valueList = values.get(name);
// Make sure that the list isn't already at capacity:
int maxOccurs = propertyDescriptor.getMaxOccurs();
if (valueList.size() == maxOccurs) {
throw new IndexOutOfBoundsException(
String.format(
"You can't add another object with the name of '%s' because you already have the maximum number (%s) allowed by the property descriptor.",
name, maxOccurs));
}
} else {
valueList = new ArrayList();
values.put(name, valueList);
}
valueList.add(value);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy