/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2006-2011, 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.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import org.geotools.referencing.CRS; import org.opengis.feature.type.AssociationDescriptor; import org.opengis.feature.type.AssociationType; import org.opengis.feature.type.AttributeDescriptor; import org.opengis.feature.type.AttributeType; import org.opengis.feature.type.ComplexType; import org.opengis.feature.type.FeatureType; import org.opengis.feature.type.FeatureTypeFactory; import org.opengis.feature.type.GeometryDescriptor; import org.opengis.feature.type.GeometryType; import org.opengis.feature.type.Name; import org.opengis.feature.type.PropertyDescriptor; import org.opengis.feature.type.PropertyType; import org.opengis.feature.type.Schema; import org.opengis.filter.Filter; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.util.InternationalString; /** * Makes building types easier by maintaining state. * <p> * For reference the builder captures the following state: <table border=1 cellpadding=0 * cellspacing=0> * <tr> * <th colspan=2 valign=top>State</th> * <th colspan=4>Property</th> * <th>Complex</th> * <th colspan=2>Feature</th> * <th colspan=3>Builder</th> * </font> </tr> * <tr> * <th>scope</th> * <th>state</th> * <th>descriptor()</th> * <th>attribute()</th> * <th>geometry()</th> * <th>association()</th> * <th>complex()</th> * <th>feature()</th> * <th>collection()</th> * <th>init()</th> * <th>reset()</th> * <th>clear()</th> * </tr> * <tr bgcolor=#BBCCAA> * <th rowspan=4 valign=top>naming</th> * <td>namespace</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td> </td> * <td> </td> * </tr> * <tr bgcolor=#BBCCAA> * <td>name</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td> </td> * </tr> * <tr bgcolor=#BBCCAA> * <td>isIdentified</td> * <td> </td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td> </td> * <td> </td> * </tr> * <tr bgcolor=#BBCCAA> * <td>description</td> * <td> </td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td> </td> * </tr> * <tr> * <th rowspan=3 valign=top>type</th> * <td>isAbstract</td> * <td> </td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td> </td> * <td> </td> * </tr> * <tr> * <td>superType</td> * <td> </td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td> </td> * <td> </td> * </tr> * <tr> * <td>restriction*</td> * <td> </td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td> </td> * <td> </td> * </tr> * <tr bgcolor=#BBCCAA> * <th>association</th> * <td>referenceType</td> * <td> </td> * <td> </td> * <td> </td> * <td>x</td> * <td> </td> * <td> </td> * <td> </td> * <td>x</td> * <td> </td> * <td> </td> * </tr> * <tr> * <th rowspan=4 valign=top>descriptor</th> * <td>minOccurs</td> * <td>x</td> * <td> </td> * <td> </td> * <td> </td> * <td> </td> * <td> </td> * <td> </td> * <td>x</td> * <td> </td> * <td>x</td> * </tr> * <tr> * <td>maxOccurs</td> * <td>x</td> * <td> </td> * <td> </td> * <td> </td> * <td> </td> * <td> </td> * <td> </td> * <td>x</td> * <td> </td> * <td>x</td> * </tr> * <tr> * <td>isNillable</td> * <td>x</td> * <td> </td> * <td> </td> * <td> </td> * <td> </td> * <td> </td> * <td> </td> * <td>x</td> * <td> </td> * <td>x</td> * </tr> * <tr> * <td>propertyType</td> * <td>x</td> * <td> </td> * <td> </td> * <td> </td> * <td> </td> * <td> </td> * <td> </td> * <td>x</td> * <td> </td> * <td> </td> * </tr> * <tr bgcolor=#BBCCAA> * <th>atomic</th> * <td>binding</td> * <td> </td> * <td>x</td> * <td>x</td> * <td> </td> * <td> </td> * <td> </td> * <td> </td> * <td>x</td> * <td> </td> * <td> </td> * </tr> * <tr> * <th>complex</th> * <td>properties*</td> * <td> </td> * <td> </td> * <td> </td> * <td> </td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td> </td> * </tr> * <tr bgcolor=#BBCCAA> * <th rowspan=2 valign=top>spatial</th> * <td>crs</td> * <td> </td> * <td> </td> * <td>x</td> * <td> </td> * <td> </td> * <td>x</td> * <td>x</td> * <td>x</td> * <td> </td> * <td> </td> * </tr> * <tr bgcolor=#BBCCAA> * <td>defaultGeom</td> * <td> </td> * <td> </td> * <td> </td> * <td> </td> * <td> </td> * <td>x</td> * <td>x</td> * <td>x</td> * <td>x</td> * <td> </td> * </tr> * <tr> * <th>collection</th> * <td>members*</td> * <td> </td> * <td> </td> * <td> </td> * <td> </td> * <td> </td> * <td> </td> * <td>x</td> * <td>x</td> * <td>x</td> * <td> </td> * </tr> * </table> * collection implementation may be specified * </p> * <p> * There are five state control methods: * <ul> * <li>{@link init( PropertyType )} - completly load settings from type * <li>{@link init( PropertyDescriptor )} - completly load settings from descriptor * <li>{@link init()} - completly replace settings with builder defaults * <ul> * <li>{@link reset()} - called after a type creation methods to reset common type settings * <li>{@link clear()} - called after an descriptor create method (or add methods) to clear common * descriptor settings * </ul> * </ul> * <p> * For examples of using this class please see the following type creation methods: * <ul> * <li>{@link attribute()} * <li>{@link geometry()} * <li>{@link association()} * <li>{@link complex()} * <li>{@link feature()} * <li>{@link collection()} * </ul> * <p> * * @author Justin Deoliveira * @author Jody Garnett * * * * @source $URL$ */ public class TypeBuilder { /** * factory for creating actual types */ private FeatureTypeFactory factory; /** * Namespace of the type, and contained types. */ private String namespace; /** * Local name of the type. */ private String name; /** * Class the built type is bound to. */ private Class<?> binding; /** * Description of type. */ private InternationalString description; /** * Flag indicating wether type is identifiable. */ private boolean isIdentified; /** * Flag indicating wether type is identifiable. */ private boolean isAbstract; /** * Additional restrictions on the type. */ private List<Filter> restrictions; /** * The parent type of the type. */ private PropertyType superType; /** * Flag indiciating wether added properties are nillable. */ private boolean isNillable; /** * Map of java class bound to properties types. * <p> * Please see */ private Map<Class<?>, AttributeType> bindings; /** * The properties of the type. */ private Collection<PropertyDescriptor> properties; /** * Minimum occurences of added properties. */ private int minOccurs; /** * Maximum occurences of added properties. */ private int maxOccurs; // // FeatureType state // private Name defaultGeom = null; private CoordinateReferenceSystem crs = null; /** Used as the target of association() */ private AttributeType referenceType; /** Members of a collection() */ protected Collection members; /** * Type used when creating descriptor. * <p> * May be either a AttributeType or AssocationType. */ private PropertyType propertyType; // // FeatureCollection state // public TypeBuilder(FeatureTypeFactory factory) { this.factory = factory; init(); } public FeatureTypeFactory getTypeFactory() { return factory; } public void setTypeFactory(FeatureTypeFactory factory) { this.factory = factory; } /** * Reset is called after creation a "new" type. * <p> * The following information is reset: * <ul> * <li>name * <li>properties: structural properties (attributes and associations) * <li>members: collection members * <li>default geometry * <li>minOccurs * <li>maxOccurs * </ul> * <p> * Note: type type of collection class is not reset, a new instanceof the existing collection * class is used. */ public void reset() { this.name = null; this.description = null; this.properties = newCollection(properties); this.members = newCollection(members); this.defaultGeom = null; } public void clear() { this.minOccurs = 1; this.maxOccurs = 1; this.isNillable = false; } /** * Initialize this builder. * <p> * This method cleans the builder of all contained state. * </p> * * @see reset */ public void init() { this.namespace = null; this.name = null; this.description = null; this.isIdentified = false; this.binding = null; isAbstract = false; restrictions = null; superType = null; properties = null; isNillable = true; minOccurs = 1; maxOccurs = 1; propertyType = null; defaultGeom = null; crs = null; referenceType = null; } public void init(PropertyDescriptor descriptor) { init(); namespace = descriptor.getName().getNamespaceURI(); name = descriptor.getName().getLocalPart(); minOccurs = descriptor.getMinOccurs(); maxOccurs = descriptor.getMaxOccurs(); if (descriptor instanceof AttributeDescriptor) { AttributeDescriptor attribute = (AttributeDescriptor) descriptor; isNillable = attribute.isNillable(); propertyType = attribute.getType(); } if (descriptor instanceof AssociationDescriptor) { AssociationDescriptor association = (AssociationDescriptor) descriptor; propertyType = association.getType(); } } public void init(PropertyType type) { init(); if (type == null) return; namespace = type.getName().getNamespaceURI(); name = type.getName().getLocalPart(); description = type.getDescription(); isAbstract = type.isAbstract(); restrictions = null; restrictions().addAll(type.getRestrictions()); if (type instanceof AssociationType) { AssociationType assType = (AssociationType) type; referenceType = assType.getRelatedType(); superType = assType.getSuper(); } if (type instanceof AttributeType) { AttributeType aType = (AttributeType) type; binding = aType.getBinding(); isIdentified = aType.isIdentified(); superType = aType.getSuper(); } if (type instanceof GeometryType) { GeometryType geometryType = (GeometryType) type; this.crs = geometryType.getCoordinateReferenceSystem(); } if (type instanceof ComplexType) { ComplexType cType = (ComplexType) type; properties = null; properties.addAll(cType.getDescriptors()); } if (type instanceof FeatureType) { FeatureType featureType = (FeatureType) type; defaultGeom = featureType.getGeometryDescriptor().getType().getName(); crs = featureType.getCoordinateReferenceSystem(); } } /** * Creation method for AttributeType. * <p> * Example: * * <pre><code> * AttributeType TEXT = builder.name("Text").bind(String.class).attribute(); * </code></pre> * * </p> * <p> * Example: * * <pre><code> * builder.setName("Interger"); * builder.setBinding(Integer.class); * AttributeType INTEGER = builder.attribute(); * </code></pre> * * </p> * * @return AttributeType created */ public AttributeType attribute() { AttributeType type = factory.createAttributeType(typeName(), getBinding(), isIdentified(), isAbstract(), restrictions(), getSuper(), getDescription()); reset(); return type; } /** Create AssociationType */ public AssociationType association() { return factory.createAssociationType(typeName(), getReferenceType(), true, this.restrictions, getAssociationSuper(), this.getDescription()); } /** * Create GeometryType. * <p> * SFSQL Example JTS LineString.class: * * <pre><code> * AttributeType ROUTE = builder.name("Route").bind(LineString.class).crs("EPSG:4326").geometry(); * </code></pre> * * Shape Example Java Rectangle2D: * * <pre><code> * builder.setName("Quad"); * builder.setBinding(Rectangle2D.class); * builder.setCRS(crs); * AttributeType QUAD = builder.geometry(); * </code></pre> * * Use of GeoAPI Geometry interfaces is encouraged as implementations are made avaiable. * */ public GeometryType geometry() { return getTypeFactory().createGeometryType(typeName(), getBinding(), getCRS(), isIdentified(), isAbstract(), restrictions(), getSuper(), getDescription()); } /** * Create a complex attribute, made up of other attributes. * <p> * Example using Set: * * <pre><code> * builder.setName("FullName"); * builder.setProperties(new HasSet()); * builder.addAttribute("first", TEXT); * builder.setMinOccurs(0); * builder.setMaxOccurs(Integer.MAX_VALUE); * builder.addAttribute("middle", TEXT); * builder.addAttribute("last", TEXT); * ComplexType FULLNAME = builder.complex(); * </code></pre> * * <p> * Example using chaining: * * <pre><code> * ComplexType FULLNAME = builder.name("FullName").attribute("first", TEXT).cardinality(0, * Integer.MAX_VALUE).attribute("middle", TEXT).attribute("last", TEXT).complex(); * </code></pre> * * @return ComplexType */ public ComplexType complex() { ComplexType type = getTypeFactory().createComplexType(typeName(), properties(), isIdentified(), isAbstract(), restrictions(), getSuper(), getDescription()); reset(); return type; } /** * Create an AttributeDesctiptor, useful for fine grain control. * <p> * Example: * * <pre><code> * AttributeDescriptor name = build.name("name").property(TEXT).cardinality(1, 5) * .attributeDescriptor(); * </code></pre> * * @return AttributeDescriptor used to define sturcture of ComplexAttribtues */ public AttributeDescriptor attributeDescriptor() { // TODO: handle default value AttributeDescriptor attribute = getTypeFactory().createAttributeDescriptor( (AttributeType) propertyType, typeName(), getMinOccurs(), getMaxOccurs(), isNillable(), null); reset(); return attribute; } /** * Create an AssociationDesctiptor, define relationships between ComplexAttribtues (in * particular FeatureCollection to members). * <p> * Example: * * <pre><code> * AttributeDescriptor contains = build.name("contains").property(ROAD).nillable(false).cardinality(0, * Interger.MAX_VALUE).associationDescriptor(); * </code></pre> * * @return AttributeDescriptor used to define sturcture of ComplexAttribtues */ public AssociationDescriptor associationDescriptor() { AssociationDescriptor association = getTypeFactory().createAssociationDescriptor( (AssociationType) propertyType, typeName(), getMinOccurs(), getMaxOccurs(), isNillable()); reset(); return association; } /** * Create feature. * * @return FeatureType */ public FeatureType feature() { // FeatureTypeFactory typeFactory = getTypeFactory(); FeatureType type = factory.createFeatureType(typeName(), properties(), defaultGeometry(), isAbstract(), restrictions(), getSuper(), getDescription()); reset(); return type; } // /** // * Creates a FeatureCollectionType. // * // * @return FeatureCollectionType based on builder state // */ // public FeatureCollectionType collection() { // FeatureCollectionType type = getTypeFactory().createFeatureCollectionType(typeName(), // properties(), members(), defaultGeometry(), getCRS(), isAbstract(), restrictions(), // getSuper(), getDescription()); // reset(); // return type; // } public void setNamespaceURI(String namespace) { this.namespace = namespace; } public String getNamespaceURI() { return namespace; } public void setName(String name) { this.name = name; } public TypeBuilder name(String name) { setName(name); return this; } public String getName() { return name; } public void setBinding(Class<?> binding) { this.binding = binding; } public TypeBuilder bind(Class<?> binding) { setBinding(binding); return this; } public PropertyType getPropertyType() { return propertyType; } public void setPropertyType(PropertyType type) { this.propertyType = type; } /** * Used as a the target for attributeDescriptor or associatioDescriptor(). * * @param type * @return TypeBuilder (for chaining). */ public TypeBuilder property(PropertyType type) { setPropertyType(type); return this; } public Class<?> getBinding() { return binding; } public InternationalString getDescription() { return description; } public void setDescription(InternationalString description) { this.description = description; } public void setAbstract(boolean isAbstract) { this.isAbstract = isAbstract; } public boolean isAbstract() { return isAbstract; } public TypeBuilder nillable(boolean isNillable) { this.isNillable = isNillable; return this; } public void setNillable(boolean isNillable) { this.isNillable = isNillable; } public boolean isNillable() { return isNillable; } public void setIdentified(boolean isIdentified) { this.isIdentified = isIdentified; } public boolean isIdentified() { return isIdentified; } public void setSuper(PropertyType superType) { this.superType = superType; } public AttributeType getSuper() { return (AttributeType) superType; } public AssociationType getAssociationSuper() { return (AssociationType) superType; } public void addRestriction(Filter restriction) { restrictions.add(restriction); } public List<Filter> getRestrictions() { return Collections.unmodifiableList(restrictions); } public void setRestrictions(List<Filter> restrictions) { this.restrictions = restrictions; } /** * Accessor for restructions which does the null check and creation if necessary. */ protected List<Filter> restrictions() { if (restrictions == null) { restrictions = createRestrictionSet(); } return restrictions; } /** * Template method to enable subclasses to customize the set implementation used for * restrictions. * * @return A HashSet. */ protected List<Filter> createRestrictionSet() { return new ArrayList<Filter>(); } /** * Accessor which returns type banme as follows: * <ol> * <li>If <code>typeName</code> has been set, its value is returned. * <li>If <code>name</code> has been set, it + <code>namespaceURI</code> are returned. * </ol> * */ protected Name typeName() { // see if local name was set if (name != null) { // qualify the name with the namespace return createTypeName(namespace, name); } // else the type is anonymous return null; } /** * Template method for creating a type name. * * @return {@link org.geotools.feature.iso.Types#typeName(String, String)} */ protected Name createTypeName(String ns, String local) { return Types.typeName(ns, local); } /** * Used to lookup AttributeType for provided binding. * * @param binding * @return AttributeType * @throws IllegalArgumentExcception * if class is not bound to a prototype */ public AttributeType getBinding(Class binding) { AttributeType type = (AttributeType) bindings().get(binding); if (type == null) { throw new IllegalArgumentException("No type bound to: " + binding); } return type; } /** * Used to provide a specific type for provided binding. * <p> * You can use this method to map the AttributeType used when addAttribute( String name, Class * binding ) is called. * * @param binding * @param type */ public void addBinding(Class binding, AttributeType type) { bindings().put(binding, type); } /** * Load the indicated schema to map Java class to your Type System. (please us a profile to * prevent binding conflicts). * * @param schema */ public void load(Schema schema) { for (Iterator itr = schema.values().iterator(); itr.hasNext();) { AttributeType type = (AttributeType) itr.next(); addBinding(type.getBinding(), type); } } public int getMinOccurs() { return minOccurs; } public TypeBuilder cardinality(int min, int max) { this.minOccurs = min; this.maxOccurs = max; return this; } public void setMinOccurs(int minOccurs) { this.minOccurs = minOccurs; } public int getMaxOccurs() { return maxOccurs; } public void setMaxOccurs(int maxOccurs) { this.maxOccurs = maxOccurs; } // // Structural Properties (Attirbute and Association) // /** * Add a descriptor with a provided name, with the binding * * @param name * Name of descriptor (combined with uri for a Name) * @param binding * Used to look up a bound AttributeType * @return this builder for additional chaining */ public TypeBuilder attribute(String name, Class binding) { return attribute(namespace, name, binding); } /** * Add a descriptor with a provided name, with the binding * * @param namespaceURI * @param name * Name of descriptor (combined with uri for a Name) * @param binding * Used to look up a bound AttributeType * @return this builder for additional chaining */ public TypeBuilder attribute(String namespaceURI, String name, Class binding) { return attribute(createName(namespaceURI, name), binding); } public TypeBuilder attribute(Name name, Class binding) { return attribute(name, getBinding(binding)); } public TypeBuilder attribute(String name, String namespaceURI, AttributeType type) { attribute(createName(namespaceURI, name), type); return this; } public TypeBuilder attribute(String name, AttributeType type) { attribute(name, getNamespaceURI(), type); return this; } public TypeBuilder attribute(Name name, AttributeType type) { // TODO: handle default value AttributeDescriptor descriptor = getTypeFactory().createAttributeDescriptor(type, name, getMinOccurs(), getMaxOccurs(), isNillable(), null); add(descriptor); return this; } public void addAttribute(String name, Class binding) { addAttribute(namespace, name, binding); } public void addAttribute(String uri, String name, Class binding) { addAttribute(createName(uri, name), binding); } public void addAttribute(Name name, Class binding) { addAttribute(name, getBinding(binding)); } public void addAttribute(String name, AttributeType type) { addAttribute(name, getNamespaceURI(), type); } public void addAttribute(String name, String namespaceURI, AttributeType type) { addAttribute(createName(namespaceURI, name), type); } public void addAttribute(Name name, AttributeType type) { // TODO: handle default value AttributeDescriptor descriptor = getTypeFactory().createAttributeDescriptor(type, name, getMinOccurs(), getMaxOccurs(), isNillable(), null); add(descriptor); } /** * Allows you to indicate the reference type to be used with Association to be created. */ public void setReferenceType(AttributeType reference) { this.referenceType = reference; } public TypeBuilder referenceType(AttributeType reference) { setReferenceType(reference); return this; } public AttributeType getReferenceType() { return referenceType; } public TypeBuilder association(String name, AssociationType type) { return association(getNamespaceURI(), name, type); } public TypeBuilder association(String namespaceURI, String name, AssociationType type) { return association(createName(namespaceURI, name), type); } public TypeBuilder association(Name name, AssociationType type) { AssociationDescriptor descriptor = getTypeFactory().createAssociationDescriptor(type, name, getMinOccurs(), getMaxOccurs(), isNillable()); add(descriptor); return this; } /** * Add provided descriptor to the type to be created. * <p> * Please note that you may not have two types with the same name, depending on the factory * being used the order of the structural content may be signficant - this builder will preserve * order although the factory may or may not make use of this fact. * </p> */ public TypeBuilder add(PropertyDescriptor descriptor) { if (!contains(properties(), descriptor)) { properties.add(descriptor); } clear(); return this; } public static boolean contains(Collection collection, PropertyDescriptor descriptor) { // check for a descriptor with the same name for (Iterator itr = collection.iterator(); itr.hasNext();) { PropertyDescriptor d = (PropertyDescriptor) itr.next(); if (d.getName().equals(descriptor.getName())) { return true; } } return false; } /** * Access to properties used by builder. * <p> * You can use this method to perform collection opperations before construction. This is most * useful when initializing the builder with a known type, performing modifications, and then * creating a derrived type. * </p> */ public Collection<PropertyDescriptor> getProperties() { if (properties == null) { properties = newCollection(); } return properties; } /** * Allow for user supplied collection implementaion used for properties. * <p> * Examples of useful property collections: * <ul> * <li>List - structured properties maintained in order * <li>Set - order of structured properties insignificant * <li>etc... * </ul> * The collection class used here should be matched by content described by this type. * Explicitly a FeatureType with <code>getProperties() instanceof Set</code> indicates that * Features of that FeatureType should maintain a Set of properties where order is not * significant. * </p> * * @param properties * Collection implementation used to organize properties */ public void setProperties(Collection<PropertyDescriptor> properties) { this.properties = properties; } // // Creation // /** * Template method to enable subclasses to customize the collection implementation used by * "default". * <p> * Considered moving this to the type interface but it would be in appropriate as the user may * need to specifiy different collections for seperate types in the same schema. * </p> * * @return Collection (subclass may override) */ protected Collection<PropertyDescriptor> newCollection() { return new HashSet<PropertyDescriptor>(); } /** * Provides an empty copy of the provided origional collection. * <p> * This method is used by reset for the following goals: * <ul> * <li>use the user supplied collection directly by the TypeFactory, * <li>remember the user supplied collection type for subsequent builder use * </ul> * This allows a user to indicate that properties are stored in a "LinkedList" once. * * @param origional * Origional collection * @return New instance of the originoal Collection */ protected Collection newCollection(Collection origional) { if (origional == null) { return newCollection(); } try { return (Collection) origional.getClass().newInstance(); } catch (InstantiationException e) { return newCollection(); } catch (IllegalAccessException e) { return newCollection(); } } // // Factory method argument preparation // /** * Grab property collection as an argument to factory method. * <p> * This may return a copy as needed, since most calls to a factory method end up with a reset * this seems not be needed at present. * </p> */ protected Collection<PropertyDescriptor> properties() { if (properties == null) { properties = newCollection(); } return properties; } /** * Accessor for bindings. */ protected Map bindings() { if (bindings == null) { bindings = new HashMap(); } return bindings; } /** * Template method for creating an attribute name. * * @return {@link org.geotools.feature.Types#typeName(String, String)} */ protected Name createName(String ns, String local) { return Types.typeName(ns, local); } public void setDefaultGeometry(String name) { setDefaultGeometry(name, getNamespaceURI()); } public void setDefaultGeometry(String name, String namespaceURI) { setDefaultGeometry(createName(namespaceURI, name)); } public void setDefaultGeometry(Name name) { defaultGeom = name; } public TypeBuilder defaultGeometry(String name) { setDefaultGeometry(name); return this; } public Name getDefaultGeometry() { return defaultGeom; } /** * Convenience method for getting the descriptor of the default geometry type. This method will * first try to look up the supplied <code>defaultGeom</code> property, if it cant find, it * will try to locate any added geometry. * */ protected GeometryDescriptor defaultGeometry() { if (defaultGeom != null) { for (PropertyDescriptor pd : properties) { if (pd.getName().equals(defaultGeom)) { return (GeometryDescriptor) pd; } } } // not found or not set, return first geometry for (PropertyDescriptor pd : properties) { if (pd instanceof GeometryDescriptor) { return (GeometryDescriptor) pd; } } return null; } public void setCRS(CoordinateReferenceSystem crs) { this.crs = crs; } public TypeBuilder crs(CoordinateReferenceSystem crs) { setCRS(crs); return this; } /** * Uses CRS utility class with buildres TypeFactory.getCRSFactory to look up a * CoordinateReferenceSystem based on the provied srs. * <p> * A SpatialReferenceSystem can be one of the following: * <ul> * <li>"AUTHORITY:CODE" * <li>Well Known Text * </ul> * * @param srs * @return TypeBuilder ready for chaining * @throws IllegalArgumentException * When SRS not understood */ public TypeBuilder crs(String SRS) { try { setCRS(CRS.decode(SRS)); } catch (Exception e) { IllegalArgumentException iae = new IllegalArgumentException("SRS '" + SRS + "' unknown:" + e); iae.initCause(e); throw iae; } return this; } public CoordinateReferenceSystem getCRS() { return crs; } // // Feature Collection // /** * Access to members used by builder. * <p> * You can use this method to perform collection opperations before construction. This is most * useful when initializing the builder with a known type, performing modifications, and then * creating a derrived type. * </p> */ public Collection getMembers() { if (members == null) { members = newCollection(); } return members; } /** Provide collection class used organize collection members */ public void setMembers(Collection members) { this.members = members; } /** * Grab member collection as an argument to factory method. * <p> * This may return a copy as needed, since most calls to a factory method end up with a reset * this seems not be needed at present. * </p> */ protected Collection members() { if (members == null) { members = newCollection(); } return members; } /** * Creates a association descriptor and adds to collection members. * <p> * Calls clear to reset cardinality after use. * </p> * * @param name * @param type */ public void addMemberType(String name, AssociationType memberType) { addMemberType(getNamespaceURI(), name, memberType); } /** * Creates a association descriptor and adds to collection members. * <p> * Calls clear to reset cardinality after use. * </p> * * @param name * @param type */ public void addMemberType(String namespaceURI, String name, AssociationType memberType) { addMemberType(createName(namespaceURI, name), memberType); } /** * Creates a association descriptor and adds to collection members. * <p> * Calls clear to reset cardinality after use. * </p> * * @param name * @param type */ public void addMemberType(Name name, AssociationType/* <FeatureType> */memberType) { member(name, memberType); } /** * Creates a association descriptor and adds to collection members. * <p> * Calls clear to reset cardinality after use. * </p> * * @param name * @param type * @return TypeBuilder for operation chaining */ public TypeBuilder member(String name, AssociationType type) { return member(createName(getNamespaceURI(), name), type); } /** * Creates a association descriptor and adds to collection members. * <p> * Calls clear to reset cardinality after use. * </p> * * @param name * @param type * @return TypeBuilder for operation chaining */ public TypeBuilder member(Name name, AssociationType type) { AssociationDescriptor descriptor = getTypeFactory().createAssociationDescriptor(type, name, getMinOccurs(), getMaxOccurs(), isNillable()); clear(); return member(descriptor); } public TypeBuilder member(AssociationDescriptor memberOf) { if (!contains(members(), memberOf)) { members.add(memberOf); } return this; } }