/* * Geotools2 - OpenSource mapping toolkit * http://geotools.org * (C) 2002, Geotools Project Managment Committee (PMC) * * 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 org.geotools.factory.Factory; import org.geotools.factory.FactoryConfigurationError; import org.geotools.factory.FactoryFinder; import java.util.Arrays; import java.util.HashSet; import java.util.Set; /** * A factory patterned object for the creation of FeatureTypes. Because * FeatureTypes are meant to be immutable, this object is mutable. * *
* The basic idea for usage is that you configure the factory to whatever state
* is desired, setting properties and adding AttributeTypes. When the desired
* state is acheived, the expected FeatureType can be retrieved by calling
* getFeatureType()
* Repeated calls to getFeatureType will return the same FeatureType
* given that no calls which modify the state of the factory are made.
*
* Here's an example of how to use this:
*
There are also a set of convenience
* methods for creation of FeatureTypes. These are the various newFeatureType
* methods.
*
* FeatureTypeFactory factory = FeatureTypeFactory.newInstance();
* factory.addType(...);
* factory.setName(...);
* factory.setNamespace(...);
* FeatureType type = factory.getFeatureType();
*
* Remember, changes to any state will invalidate the current FeatureType,
* if one exists
* This class is not thread-safe.
*
* FeatureTypeFactory factory = FeatureTypeFactory.newInstace();
* factory.importType(yourTypeHere);
* factory.setName(original.getName());
* factory.setNamespace(original.getNamespace());
* factory.setNillable(original.isNillable());
* factory.setDefaultGeometry(original.getDefaultGeometry());
*
*
* @param original The FeatureType to obtain information from.
*
* @return A new FeatureTypeFactory which is initialized with the state of
* the original FeatureType.
*
* @throws FactoryConfigurationError If a FeatureTypeFactory cannot be
* found.
*/
public static FeatureTypeFactory createTemplate(FeatureType original)
throws FactoryConfigurationError {
FeatureTypeFactory factory = newInstance(original.getTypeName());
factory.importType(original);
factory.setNamespace(original.getNamespace());
factory.setDefaultGeometry(original.getDefaultGeometry());
FeatureType[] ancestors = original.getAncestors();
if (ancestors != null) {
factory.setSuperTypes(Arrays.asList(ancestors));
}
return factory;
}
/**
* The most specific way to create a new FeatureType.
*
* @param types The AttributeTypes to create the FeatureType with.
* @param name The typeName of the FeatureType. Required, may not be null.
* @param ns The namespace of the FeatureType. Optional, may be null.
* @param isAbstract True if this created type should be abstract.
* @param superTypes A Collection of types the FeatureType will inherit
* from. Currently, all types inherit from feature in the opengis
* namespace.
*
* @return A new FeatureType created from the given arguments.
*
* @throws FactoryConfigurationError If there are problems creating a
* factory.
* @throws SchemaException If the AttributeTypes provided are invalid in
* some way.
*/
public static FeatureType newFeatureType(AttributeType[] types,
String name, String ns, boolean isAbstract, FeatureType[] superTypes)
throws FactoryConfigurationError, SchemaException {
return newFeatureType(types, name, ns, isAbstract, superTypes, null);
}
/**
* The most specific way to create a new FeatureType.
*
* @param types The AttributeTypes to create the FeatureType with.
* @param name The typeName of the FeatureType. Required, may not be null.
* @param ns The namespace of the FeatureType. Optional, may be null.
* @param isAbstract True if this created type should be abstract.
* @param superTypes A Collection of types the FeatureType will inherit
* from. Currently, all types inherit from feature in the opengis
* namespace.
*
* @return A new FeatureType created from the given arguments.
*
* @throws FactoryConfigurationError If there are problems creating a
* factory.
* @throws SchemaException If the AttributeTypes provided are invalid in
* some way.
*/
public static FeatureType newFeatureType(AttributeType[] types,
String name, String ns, boolean isAbstract, FeatureType[] superTypes, AttributeType defaultGeometry)
throws FactoryConfigurationError, SchemaException {
FeatureTypeFactory factory = newInstance(name);
factory.addTypes(types);
factory.setNamespace(ns);
factory.setAbstract(isAbstract);
if(defaultGeometry != null)
factory.setDefaultGeometry((GeometryAttributeType) defaultGeometry);
if (superTypes != null) {
factory.setSuperTypes(Arrays.asList(superTypes));
}
return factory.getFeatureType();
}
/**
* The most specific way to create a new FeatureType.
*
* @param types The AttributeTypes to create the FeatureType with.
* @param name The typeName of the FeatureType. Required, may not be null.
* @param ns The namespace of the FeatureType. Optional, may be null.
* @param isAbstract True if this created type should be abstract.
* @param superTypes A Collection of types the FeatureType will inherit
* from. Currently, all types inherit from feature in the opengis
* namespace.
*
* @return A new FeatureType created from the given arguments.
*
* @throws FactoryConfigurationError If there are problems creating a
* factory.
* @throws SchemaException If the AttributeTypes provided are invalid in
* some way.
*/
public static FeatureType newFeatureType(AttributeType[] types,
String name, String ns, boolean isAbstract, FeatureType[] superTypes, GeometryAttributeType defaultGeometry)
throws FactoryConfigurationError, SchemaException {
FeatureTypeFactory factory = newInstance(name);
factory.addTypes(types);
factory.setNamespace(ns);
factory.setAbstract(isAbstract);
if (superTypes != null) {
factory.setSuperTypes(Arrays.asList(superTypes));
}
if(defaultGeometry != null) {
factory.setDefaultGeometry(defaultGeometry);
}
return factory.getFeatureType();
}
/**
* Create a new FeatureType with the given AttributeTypes. A short cut for
* calling newFeatureType(types,name,ns,isAbstract,null)
.
*
* @param types The AttributeTypes to create the FeatureType with.
* @param name The typeName of the FeatureType. Required, may not be null.
* @param ns The namespace of the FeatureType. Optional, may be null.
* @param isAbstract True if this created type should be abstract.
*
* @return A new FeatureType created from the given arguments.
*
* @throws FactoryConfigurationError If there are problems creating a
* factory.
* @throws SchemaException If the AttributeTypes provided are invalid in
* some way.
*/
public static FeatureType newFeatureType(AttributeType[] types,
String name, String ns, boolean isAbstract)
throws FactoryConfigurationError, SchemaException {
return newFeatureType(types, name, ns, isAbstract, null);
}
/**
* Create a new FeatureType with the given AttributeTypes. A short cut for
* calling newFeatureType(types,name,ns,false,null)
.
*
* @param types The AttributeTypes to create the FeatureType with.
* @param name The typeName of the FeatureType. Required, may not be null.
* @param ns The namespace of the FeatureType. Optional, may be null.
*
* @return A new FeatureType created from the given arguments.
*
* @throws FactoryConfigurationError If there are problems creating a
* factory.
* @throws SchemaException If the AttributeTypes provided are invalid in
* some way.
*/
public static FeatureType newFeatureType(AttributeType[] types,
String name, String ns)
throws FactoryConfigurationError, SchemaException {
return newFeatureType(types, name, ns, false);
}
/**
* Create a new FeatureType with the given AttributeTypes. A short cut for
* calling newFeatureType(types,name,null,false,null)
. Useful
* for test cases or datasources which may not allow a namespace.
*
* @param types The AttributeTypes to create the FeatureType with.
* @param name The typeName of the FeatureType. Required, may not be null.
*
* @return A new FeatureType created from the given arguments.
*
* @throws FactoryConfigurationError If there are problems creating a
* factory.
* @throws SchemaException If the AttributeTypes provided are invalid in
* some way.
*/
public static FeatureType newFeatureType(AttributeType[] types, String name)
throws FactoryConfigurationError, SchemaException {
return newFeatureType(types, name, null, false);
}
/**
* Create a new FeatureTypeFactory with the given typeName.
*
* @param name The typeName of the feature to create.
*
* @return A new FeatureTypeFactory instance.
*
* @throws FactoryConfigurationError If there exists a configuration error.
*/
public static FeatureTypeFactory newInstance(String name)
throws FactoryConfigurationError {
FeatureTypeFactory factory = (FeatureTypeFactory) FactoryFinder
.findFactory("org.geotools.feature.FeatureTypeFactory",
"org.geotools.feature.DefaultFeatureTypeFactory");
factory.setName(name);
return factory;
}
/**
* Import all of the AttributeTypes from the given FeatureType into this
* factory.
*
* * If strict is true, non-uniquely named AttributeTypes will throw an * exception. *
* ** If strict is false, these will be silently ignored, but not added. *
* ** No other information is imported. *
* * @param type The FeatureType to import from. * @param strict Enforce namespace restrictions. * * @throws IllegalArgumentException If strict is true and there are naming * problems. */ public void importType(FeatureType type, boolean strict) throws IllegalArgumentException { for (int i = 0, ii = type.getAttributeCount(); i < ii; i++) { try { addType(type.getAttributeType(i)); } catch (IllegalArgumentException iae) { if (strict) { throw iae; } } } } /** * Set the super types of this factory. The types will be copied into a * Set. * * @param types A Collection of types. */ public final void setSuperTypes(java.util.Collection types) { superTypes = new java.util.LinkedHashSet(types); } /** * Obtain the super types of this factory. Any user types will be appended * to the built in types of this factory. * * @return A Collection representing the super types of the FeatureType * this factory will create. */ public final java.util.Collection getSuperTypes() { Set supers = (superTypes == null) ? new HashSet() : superTypes; Set builtin = getBuiltinTypes(); if (builtin != null) { supers.addAll(builtin); } return supers; } /** * A convienence method for importing AttributeTypes, simply calls importType(type,false)
*
* @param type The type to import.
*/
public void importType(FeatureType type) {
importType(type, false);
}
/**
* Set the name of the FeatureType this factory will produce.
*
* @param name The new name. May be null.
*/
public void setName(String name) {
dirty |= isDifferent(name, this.name);
this.name = name;
}
/**
* Get the current configuration of the name of this factory.
*
* @return The current name. May be null.
*/
public final String getName() {
return name;
}
/**
* Set the namespace of the FeatureType this factory will produce.
*
* @param namespace The new namespace. May be null.
*/
public void setNamespace(String namespace) {
dirty |= isDifferent(namespace, this.namespace);
this.namespace = namespace;
}
/**
* Get the current configuration of the namespace of this factory.
*
* @return The current namespace. May be null.
*/
public final String getNamespace() {
return namespace;
}
/**
* Is this factory configured to be abstract?
*
* @return True if it is, false if it aint.
*/
public final boolean isAbstract() {
return abstractType;
}
/**
* Configure this factory to produce an abstract type.
*
* @param a True or false.
*/
public final void setAbstract(boolean a) {
dirty = true;
this.abstractType = a;
}
private boolean isDifferent(String s1, String s2) {
if (s1 != null) {
return !s1.equals(s2);
}
if (s2 != null) {
return !s2.equals(s1);
}
return s1 != s2;
}
/**
* Remove all the AttributeTypes in this factory.
*/
public final void removeAll() {
int cnt = getAttributeCount();
for (int i = cnt; i > 0; i++) {
removeType(i - 1);
}
}
/**
* Add an array of AttributeTypes to this factory.
*
* @param types The types or a null array.
*
* @throws NullPointerException If any of the types are null.
* @throws IllegalArgumentException If there are naming problems.
*/
public final void addTypes(AttributeType[] types)
throws NullPointerException, IllegalArgumentException {
if (types == null) {
return;
}
for (int i = 0; i < types.length; i++) {
addType(types[i]);
}
}
/**
* A the given AttributeType to this factory.
*
* @param type The type to add.
*
* @throws NullPointerException If the type is null.
* @throws IllegalArgumentException If another type exists with the same
* name.
*/
public final void addType(AttributeType type)
throws NullPointerException, IllegalArgumentException {
if (type == null) {
throw new NullPointerException("type");
}
dirty = true;
check(type);
add(type);
}
/**
* Remove the given type from this factory.
*
* @param type The type to remove.
*
* @throws NullPointerException If the type is null.
*/
public final void removeType(AttributeType type)
throws NullPointerException {
if (type == null) {
throw new NullPointerException("type");
}
dirty = true;
AttributeType removed = remove(type);
if (removed == defaultGeometry) {
defaultGeometry = null;
}
}
/**
* Insert the given type at the index specified.
*
* @param idx The index to insert at.
* @param type The AttributeType to insert.
*
* @throws NullPointerException If the type is null.
* @throws IllegalArgumentException If the AttributeType is not allowed.
* @throws ArrayIndexOutOfBoundsException If the index is out of range.
*/
public final void addType(int idx, AttributeType type)
throws NullPointerException, IllegalArgumentException,
ArrayIndexOutOfBoundsException {
if (type == null) {
throw new NullPointerException("type");
}
dirty = true;
check(type);
add(idx, type);
}
/**
* Remove the AttributeType at the given index.
*
* @param idx The index to remove at.
*
* @throws ArrayIndexOutOfBoundsException If the index is out of bounds.
*/
public final void removeType(int idx) throws ArrayIndexOutOfBoundsException {
dirty = true;
AttributeType removed = remove(idx);
if (removed == defaultGeometry) {
defaultGeometry = null;
}
}
/**
* Set the AttributeType at the given index. Overwrites the existing type.
*
* @param idx The index to use.
* @param type The type to use.
*
* @throws IllegalArgumentException If the type is not good.
* @throws NullPointerException if they type passed in is null
* @throws ArrayIndexOutOfBoundsException if the index is out of bounds.
*/
public final void setType(int idx, AttributeType type)
throws IllegalArgumentException, NullPointerException,
ArrayIndexOutOfBoundsException {
if (type == null) {
throw new NullPointerException("type");
}
dirty = true;
check(type);
AttributeType removed = set(idx, type);
if (removed == defaultGeometry) {
defaultGeometry = null;
}
}
/**
* Swap the AttributeTypes at the given locations.
*
* @param idx1 The index of the first.
* @param idx2 The index of the second.
*
* @throws ArrayIndexOutOfBoundsException if either index is not in the
* array bounds.
*/
public final void swap(int idx1, int idx2)
throws ArrayIndexOutOfBoundsException {
// implementation note:
// we must rely on the subclass implementation, which, hopefully does
// not do any checking. If we used setType, there is a name overlap.
AttributeType tmp = get(idx1);
set(idx1, get(idx2));
set(idx2, tmp);
// must do this!
dirty = true;
}
/**
* Return the AttributeType currently used as the defaultGeometry property
* for the FeatureType this factory will create.
*
* @return The AttributeType representing the defaultGeometry or null.
*/
public final GeometryAttributeType getDefaultGeometry() {
return defaultGeometry;
}
/**
* Sets the defaultGeometry of this factory. If the defaultGeometry
* AttributeType does not exist as an AttributeType within this factory,
* it is added. This will overwrite the existing defaultGeometry, yet not
* remove it from the existing AttributeTypes.
*
* @param defaultGeometry The AttributeType to use as the defaultGeometry.
* May be null.
*
* @throws IllegalArgumentException if the type is not a geometry.
*/
public final void setDefaultGeometry(GeometryAttributeType defaultGeometry)
throws IllegalArgumentException {
// check if Geometry
if ((defaultGeometry != null) && !defaultGeometry.isGeometry()) {
String mess = "Attempted to set a non-geometry type as "
+ "defaultGeometry: ";
throw new IllegalArgumentException(mess + defaultGeometry);
}
dirty = true; // do this!
this.defaultGeometry = defaultGeometry;
// if the defaultGeometry hasn't been added, add it!
if ((defaultGeometry != null) && !contains(defaultGeometry)) {
addType(defaultGeometry);
}
}
/**
* Get a FeatureType which reflects the state of this factory. Any
* modifications to the state of the factory (adding, removing, or
* reordering any AttributeTypes or changing any other properties -
* isNillable,name,etc.), will cause the factory to "retool" itself. If
* the factory has not changed since a call to this method, the return
* value will be the same FeatureType which the previous method returned.
* Otherwise, a new FeatureType will be created.
*
* @return The featureType reflecting the current factory state.
*
* @throws SchemaException if name is null or blank
*/
public final FeatureType getFeatureType() throws SchemaException {
// we're dirty, recreate the FeatureType
if (dirty || (type == null)) {
// no defaultGeometry assigned, search for one.
if (defaultGeometry == null) {
for (int i = 0, ii = getAttributeCount(); i < ii; i++) {
if (get(i) instanceof GeometryAttributeType) {
defaultGeometry = (GeometryAttributeType) get(i);
break;
}
}
}
if ((name == null) || (name.trim().length() == 0)) {
throw new SchemaException(
"Cannot create FeatureType with null or blank name");
}
type = createFeatureType();
// oops, the subclass messed up...
if (type == null) {
throw new NullPointerException(getClass().getName()
+ ".createFeatureType()");
}
if (isAbstract() && !type.isAbstract()) {
throw new RuntimeException(
"FeatureTypeFactory poorly implemented, "
+ "expected abstract type, received " + type);
}
// not dirty anymore.
dirty = false;
}
return type;
}
/**
* Returns a string representation of this factory.
*
* @return The string representing this factory.
*/
public String toString() {
String types = "";
for (int i = 0, ii = getAttributeCount(); i < ii; i++) {
types += get(i);
if (i < ii) {
types += " , ";
}
}
return "FeatureTypeFactory(" + getClass().getName() + ") [ " + types
+ " ]";
}
/**
* Check to see if this factory contains the given AttributeType. The
* comparison is done by name.
*
* @param type The AttributeType to search for by name.
*
* @return true if a like-named AttributeType exists,
* false otherwise.
*/
public final boolean contains(AttributeType type) {
for (int i = 0, ii = getAttributeCount(); i < ii; i++) {
if (get(i).getName().equals(type.getName())) {
return true;
}
}
return false;
}
/**
* Checks to see if this factory already contains the type.
*
* @param type
*
* @throws IllegalArgumentException DOCUMENT ME!
*/
protected void check(AttributeType type) {
if (contains(type)) {
throw new IllegalArgumentException("Duplicate AttributeTypes "
+ type);
}
}
protected final Set getBuiltinTypes() {
if ((builtInTypes == null) && !initialized) {
builtInTypes = new HashSet();
try {
builtInTypes.add(newFeatureType(null, "Feature",
"http://www.opengis.net/gml", true));
initialized = true;
} catch (Exception e) {
throw new RuntimeException(e);
}
addBaseTypes(builtInTypes);
}
return builtInTypes;
}
protected void addBaseTypes(Set types) {
// base class hook
}
/**
* DOCUMENT ME!
*
* @return
*/
protected abstract FeatureType createFeatureType()
throws SchemaException;
/**
* DOCUMENT ME!
*
* @param type
*
* @throws IllegalArgumentException
*/
protected abstract void add(AttributeType type)
throws IllegalArgumentException;
/**
* DOCUMENT ME!
*
* @param type
*
* @return
*/
protected abstract AttributeType remove(AttributeType type);
/**
* DOCUMENT ME!
*
* @param idx
* @param type
*
* @throws ArrayIndexOutOfBoundsException
* @throws IllegalArgumentException
*/
protected abstract void add(int idx, AttributeType type)
throws ArrayIndexOutOfBoundsException, IllegalArgumentException;
/**
* DOCUMENT ME!
*
* @param idx
*
* @return
*
* @throws ArrayIndexOutOfBoundsException
*/
protected abstract AttributeType remove(int idx)
throws ArrayIndexOutOfBoundsException;
/**
* DOCUMENT ME!
*
* @param idx
*
* @return
*
* @throws ArrayIndexOutOfBoundsException
*/
public abstract AttributeType get(int idx)
throws ArrayIndexOutOfBoundsException;
/**
* DOCUMENT ME!
*
* @param idx
* @param type
*
* @return
*
* @throws ArrayIndexOutOfBoundsException
* @throws IllegalArgumentException
*/
protected abstract AttributeType set(int idx, AttributeType type)
throws ArrayIndexOutOfBoundsException, IllegalArgumentException;
/**
* DOCUMENT ME!
*
* @return
*/
public abstract int getAttributeCount();
}