0001: /*
0002: * GeoTools - OpenSource mapping toolkit
0003: * http://geotools.org
0004: * (C) 2003-2006, GeoTools Project Managment Committee (PMC)
0005: *
0006: * This library is free software; you can redistribute it and/or
0007: * modify it under the terms of the GNU Lesser General Public
0008: * License as published by the Free Software Foundation;
0009: * version 2.1 of the License.
0010: *
0011: * This library is distributed in the hope that it will be useful,
0012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * Lesser General Public License for more details.
0015: */
0016: package org.geotools.data;
0017:
0018: import java.io.File;
0019: import java.io.IOException;
0020: import java.net.URI;
0021: import java.net.URISyntaxException;
0022: import java.net.URL;
0023: import java.util.Arrays;
0024: import java.util.Collection;
0025: import java.util.Date;
0026: import java.util.HashMap;
0027: import java.util.HashSet;
0028: import java.util.Iterator;
0029: import java.util.LinkedHashMap;
0030: import java.util.LinkedList;
0031: import java.util.List;
0032: import java.util.Map;
0033: import java.util.NoSuchElementException;
0034: import java.util.Set;
0035: import java.util.StringTokenizer;
0036: import java.util.Map.Entry;
0037:
0038: import org.geotools.data.collection.CollectionDataStore;
0039: import org.geotools.factory.CommonFactoryFinder;
0040: import org.geotools.feature.AttributeType;
0041: import org.geotools.feature.AttributeTypeFactory;
0042: import org.geotools.feature.DefaultFeatureType;
0043: import org.geotools.feature.Feature;
0044: import org.geotools.feature.FeatureCollection;
0045: import org.geotools.feature.FeatureCollections;
0046: import org.geotools.feature.FeatureIterator;
0047: import org.geotools.feature.FeatureType;
0048: import org.geotools.feature.FeatureTypeFactory;
0049: import org.geotools.feature.GeometryAttributeType;
0050: import org.geotools.feature.IllegalAttributeException;
0051: import org.geotools.feature.SchemaException;
0052: import org.geotools.feature.type.GeometricAttributeType;
0053: import org.geotools.filter.FilterAttributeExtractor;
0054: import org.geotools.filter.visitor.DefaultFilterVisitor;
0055: import org.geotools.metadata.iso.citation.Citations;
0056: import org.geotools.referencing.CRS;
0057: import org.opengis.filter.And;
0058: import org.opengis.filter.ExcludeFilter;
0059: import org.opengis.filter.Filter;
0060: import org.opengis.filter.FilterFactory;
0061: import org.opengis.filter.FilterVisitor;
0062: import org.opengis.filter.Id;
0063: import org.opengis.filter.IncludeFilter;
0064: import org.opengis.filter.Not;
0065: import org.opengis.filter.Or;
0066: import org.opengis.filter.PropertyIsBetween;
0067: import org.opengis.filter.PropertyIsEqualTo;
0068: import org.opengis.filter.PropertyIsGreaterThan;
0069: import org.opengis.filter.PropertyIsGreaterThanOrEqualTo;
0070: import org.opengis.filter.PropertyIsLessThan;
0071: import org.opengis.filter.PropertyIsLessThanOrEqualTo;
0072: import org.opengis.filter.PropertyIsLike;
0073: import org.opengis.filter.PropertyIsNotEqualTo;
0074: import org.opengis.filter.PropertyIsNull;
0075: import org.opengis.filter.expression.Add;
0076: import org.opengis.filter.expression.Divide;
0077: import org.opengis.filter.expression.Expression;
0078: import org.opengis.filter.expression.ExpressionVisitor;
0079: import org.opengis.filter.expression.Function;
0080: import org.opengis.filter.expression.Literal;
0081: import org.opengis.filter.expression.Multiply;
0082: import org.opengis.filter.expression.NilExpression;
0083: import org.opengis.filter.expression.PropertyName;
0084: import org.opengis.filter.expression.Subtract;
0085: import org.opengis.filter.spatial.BBOX;
0086: import org.opengis.filter.spatial.Beyond;
0087: import org.opengis.filter.spatial.Contains;
0088: import org.opengis.filter.spatial.Crosses;
0089: import org.opengis.filter.spatial.DWithin;
0090: import org.opengis.filter.spatial.Disjoint;
0091: import org.opengis.filter.spatial.Equals;
0092: import org.opengis.filter.spatial.Intersects;
0093: import org.opengis.filter.spatial.Overlaps;
0094: import org.opengis.filter.spatial.Touches;
0095: import org.opengis.filter.spatial.Within;
0096: import org.opengis.metadata.Identifier;
0097: import org.opengis.referencing.crs.CoordinateReferenceSystem;
0098:
0099: import com.vividsolutions.jts.geom.Coordinate;
0100: import com.vividsolutions.jts.geom.Envelope;
0101: import com.vividsolutions.jts.geom.Geometry;
0102: import com.vividsolutions.jts.geom.GeometryCollection;
0103: import com.vividsolutions.jts.geom.GeometryFactory;
0104: import com.vividsolutions.jts.geom.LineString;
0105: import com.vividsolutions.jts.geom.LinearRing;
0106: import com.vividsolutions.jts.geom.MultiLineString;
0107: import com.vividsolutions.jts.geom.MultiPoint;
0108: import com.vividsolutions.jts.geom.MultiPolygon;
0109: import com.vividsolutions.jts.geom.Point;
0110: import com.vividsolutions.jts.geom.Polygon;
0111:
0112: /**
0113: * Utility functions for use when implementing working with data classes.
0114: * <p>
0115: * TODO: Move FeatureType manipulation to feature package
0116: * </p>
0117: * @author Jody Garnett, Refractions Research
0118: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/data/DataUtilities.java $
0119: */
0120: public class DataUtilities {
0121: static Map typeMap = new LinkedHashMap();
0122:
0123: static FilterFactory ff = CommonFactoryFinder
0124: .getFilterFactory(null);
0125:
0126: static {
0127: typeMap.put("String", String.class);
0128: typeMap.put("string", String.class);
0129: typeMap.put("\"\"", String.class);
0130: typeMap.put("Integer", Integer.class);
0131: typeMap.put("int", Integer.class);
0132: typeMap.put("0", Integer.class);
0133: typeMap.put("Double", Double.class);
0134: typeMap.put("double", Double.class);
0135: typeMap.put("0.0", Double.class);
0136: typeMap.put("Float", Float.class);
0137: typeMap.put("float", Float.class);
0138: typeMap.put("0.0f", Float.class);
0139: typeMap.put("Boolean", Boolean.class);
0140: typeMap.put("true", Boolean.class);
0141: typeMap.put("false", Boolean.class);
0142: typeMap.put("Geometry", Geometry.class);
0143: typeMap.put("Point", Point.class);
0144: typeMap.put("LineString", LineString.class);
0145: typeMap.put("Polygon", Polygon.class);
0146: typeMap.put("MultiPoint", MultiPoint.class);
0147: typeMap.put("MultiLineString", MultiLineString.class);
0148: typeMap.put("MultiPolygon", MultiPolygon.class);
0149: typeMap.put("GeometryCollection", GeometryCollection.class);
0150: typeMap.put("Date", Date.class);
0151: }
0152:
0153: /**
0154: * DOCUMENT ME!
0155: *
0156: * @param featureType DOCUMENT ME!
0157: *
0158: * @return DOCUMENT ME!
0159: */
0160: public static String[] attributeNames(FeatureType featureType) {
0161: String[] names = new String[featureType.getAttributeCount()];
0162: final int count = featureType.getAttributeCount();
0163: for (int i = 0; i < count; i++) {
0164: names[i] = featureType.getAttributeType(i).getName();
0165: }
0166:
0167: return names;
0168: }
0169:
0170: /**
0171: * Takes a URL and converts it to a File. The attempts to deal with
0172: * Windows UNC format specific problems, specifically files located
0173: * on network shares and different drives.
0174: *
0175: * If the URL.getAuthority() returns null or is empty, then only the
0176: * url's path property is used to construct the file. Otherwise, the
0177: * authority is prefixed before the path.
0178: *
0179: * It is assumed that url.getProtocol returns "file".
0180: *
0181: * Authority is the drive or network share the file is located on.
0182: * Such as "C:", "E:", "\\fooServer"
0183: *
0184: * @param url a URL object that uses protocol "file"
0185: * @return a File that corresponds to the URL's location
0186: */
0187: public static File urlToFile(URL url) {
0188: String auth = url.getAuthority();
0189: String path = url.getPath();
0190: File f = null;
0191: if (auth != null && !auth.equals("")) {
0192: f = new File("//" + auth + path);
0193: } else {
0194: f = new File(path);
0195: }
0196: return f;
0197: }
0198:
0199: /**
0200: * Traverses the filter and returns any encoutered property names.
0201: * <p>
0202: * The feautre type is supplied as contexts used to lookup expressions in cases where the
0203: * attributeName does not match the actual name of the type.
0204: * </p>
0205: */
0206: public static String[] attributeNames(Filter filter,
0207: final FeatureType featureType) {
0208: if (filter == null) {
0209: return new String[0];
0210: }
0211: FilterAttributeExtractor attExtractor = new FilterAttributeExtractor(
0212: featureType);
0213: filter.accept(attExtractor, null);
0214: String[] attributeNames = attExtractor.getAttributeNames();
0215: return attributeNames;
0216: }
0217:
0218: /**
0219: * Traverses the filter and returns any encoutered property names.
0220: * @deprecated use {@link #attributeNames(Filter, FeatureType)}/
0221: */
0222: public static String[] attributeNames(Filter filter) {
0223: return attributeNames(filter, null);
0224: }
0225:
0226: /**
0227: * Traverses the expression and returns any encoutered property names.
0228: * <p>
0229: * The feautre type is supplied as contexts used to lookup expressions in cases where the
0230: * attributeName does not match the actual name of the type.
0231: * </p>
0232: */
0233: public static String[] attributeNames(Expression expression,
0234: final FeatureType featureType) {
0235: if (expression == null) {
0236: return new String[0];
0237: }
0238: FilterAttributeExtractor attExtractor = new FilterAttributeExtractor(
0239: featureType);
0240: expression.accept(attExtractor, null);
0241: String[] attributeNames = attExtractor.getAttributeNames();
0242: return attributeNames;
0243: }
0244:
0245: /**
0246: * Traverses the expression and returns any encoutered property names.
0247: * @deprecated use {@link #attributeNames(Expression, FeatureType)}/
0248: */
0249: public static String[] attributeNames(Expression expression) {
0250: return attributeNames(expression, null);
0251: }
0252:
0253: /**
0254: *
0255: * @param filter DOCUMENT ME!
0256: * @param visitor DOCUMENT ME!
0257: */
0258: public static void traverse(Filter filter, FilterVisitor visitor) {
0259: traverse(traverseDepth(filter), visitor);
0260: }
0261:
0262: /**
0263: *
0264: * @param expression DOCUMENT ME!
0265: * @param visitor DOCUMENT ME!
0266: */
0267: public static void traverse(Expression expression,
0268: FilterVisitor visitor) {
0269: traverse(traverseDepth(expression), visitor);
0270: }
0271:
0272: /**
0273: * Performs a depth first traversal on Filter.
0274: *
0275: * <p>
0276: * Filters can contain Expressions and other Filters, this method will call
0277: * visitor.visit( Filter ) and visitor.visit( Expression )
0278: * </p>
0279: *
0280: * @param set Set of Filter and Expression information
0281: * @param visitor Vistor to traverse across set
0282: */
0283: public static void traverse(Set set, final FilterVisitor visitor) {
0284: for (Iterator i = set.iterator(); i.hasNext();) {
0285: Object here = i.next();
0286:
0287: if (here instanceof Filter) {
0288: ((Filter) here).accept(visitor, null);
0289: } else if (here instanceof Expression) {
0290: if (!(visitor instanceof ExpressionVisitor)) {
0291: throw new IllegalArgumentException(
0292: "visitor is not an ExpressionVisitor");
0293: }
0294: ((Expression) here).accept((ExpressionVisitor) visitor,
0295: null);
0296: } else {
0297: throw new IllegalArgumentException(
0298: "Not a Filter or an Expression: " + here);
0299: }
0300: // if (here instanceof BetweenFilter) {
0301: // visitor.visit((BetweenFilter) here);
0302: // } else if (here instanceof CompareFilter) {
0303: // visitor.visit((CompareFilter) here);
0304: // } else if (here instanceof GeometryFilter) {
0305: // visitor.visit((GeometryFilter) here);
0306: // } else if (here instanceof LikeFilter) {
0307: // visitor.visit((LikeFilter) here);
0308: // } else if (here instanceof LogicFilter) {
0309: // visitor.visit((LogicFilter) here);
0310: // } else if (here instanceof NullFilter) {
0311: // visitor.visit((NullFilter) here);
0312: // } else if (here instanceof FidFilter) {
0313: // visitor.visit((FidFilter) here);
0314: // } else if (here instanceof Filter) {
0315: // visitor.visit((org.geotools.filter.Filter) here);
0316: // } else if (here instanceof AttributeExpression) {
0317: // visitor.visit((AttributeExpression) here);
0318: // } else if (here instanceof LiteralExpression) {
0319: // visitor.visit((LiteralExpression) here);
0320: // } else if (here instanceof MathExpression) {
0321: // visitor.visit((MathExpression) here);
0322: // } else if (here instanceof FunctionExpression) {
0323: // visitor.visit((FunctionExpression) here);
0324: // } else if (here instanceof Expression) {
0325: // visitor.visit((org.geotools.filter.Filter) here);
0326: // }
0327: }
0328: }
0329:
0330: /**
0331: * Performs a depth first traversal of Filter.
0332: *
0333: * @param filter
0334: *
0335: * @return Set of Filters in traversing filter
0336: */
0337: public static Set traverseDepth(Filter filter) {
0338: final Set set = new HashSet();
0339: FilterVisitor traverse = new Traversal() {
0340: void traverse(Filter f) {
0341: set.add(f);
0342: }
0343:
0344: void traverse(Expression expression) {
0345: set.add(expression);
0346: }
0347: };
0348:
0349: filter.accept(traverse, null);
0350:
0351: return set;
0352: }
0353:
0354: /**
0355: * Performs a depth first traversal of Filter.
0356: *
0357: * @param expression
0358: *
0359: * @return Set of Filters in traversing filter
0360: */
0361: public static Set traverseDepth(Expression expression) {
0362: final Set set = new HashSet();
0363: ExpressionVisitor traverse = new Traversal() {
0364: void traverse(Filter f) {
0365: set.add(f);
0366: }
0367:
0368: void traverse(Expression expr) {
0369: set.add(expr);
0370: }
0371: };
0372:
0373: expression.accept(traverse, null);
0374:
0375: return set;
0376: }
0377:
0378: /**
0379: * Compare operation for FeatureType.
0380: *
0381: * <p>
0382: * Results in:
0383: * </p>
0384: *
0385: * <ul>
0386: * <li>
0387: * 1: if typeA is a sub type/reorder/renamespace of typeB
0388: * </li>
0389: * <li>
0390: * 0: if typeA and typeB are the same type
0391: * </li>
0392: * <li>
0393: * -1: if typeA is not subtype of typeB
0394: * </li>
0395: * </ul>
0396: *
0397: * <p>
0398: * Comparison is based on AttributeTypes, an IOException is thrown if the
0399: * AttributeTypes are not compatiable.
0400: * </p>
0401: *
0402: * <p>
0403: * Namespace is not considered in this opperations. You may still need to
0404: * reType to get the correct namesapce, or reorder.
0405: * </p>
0406: *
0407: * @param typeA FeatureType beind compared
0408: * @param typeB FeatureType being compared against
0409: *
0410: */
0411: public static int compare(FeatureType typeA, FeatureType typeB) {
0412: if (typeA == typeB) {
0413: return 0;
0414: }
0415:
0416: if (typeA == null) {
0417: return -1;
0418: }
0419:
0420: if (typeB == null) {
0421: return -1;
0422: }
0423:
0424: int countA = typeA.getAttributeCount();
0425: int countB = typeB.getAttributeCount();
0426:
0427: if (countA > countB) {
0428: return -1;
0429: }
0430:
0431: // may still be the same featureType
0432: // (Perhaps they differ on namespace?)
0433: AttributeType a;
0434:
0435: // may still be the same featureType
0436: // (Perhaps they differ on namespace?)
0437: int match = 0;
0438:
0439: for (int i = 0; i < countA; i++) {
0440: a = typeA.getAttributeType(i);
0441:
0442: if (isMatch(a, typeB.getAttributeType(i))) {
0443: match++;
0444: } else if (isMatch(a, typeB.getAttributeType(a.getName()))) {
0445: // match was found in a different position
0446: } else {
0447: // cannot find any match for Attribute in typeA
0448: return -1;
0449: }
0450: }
0451:
0452: if ((countA == countB) && (match == countA)) {
0453: // all attributes in typeA agreed with typeB
0454: // (same order and type)
0455: // if (typeA.getNamespace() == null) {
0456: // if(typeB.getNamespace() == null) {
0457: // return 0;
0458: // } else {
0459: // return 1;
0460: // }
0461: // } else if(typeA.getNamespace().equals(typeB.getNamespace())) {
0462: // return 0;
0463: // } else {
0464: // return 1;
0465: // }
0466: return 0;
0467: }
0468:
0469: return 1;
0470: }
0471:
0472: /**
0473: * DOCUMENT ME!
0474: *
0475: * @param a DOCUMENT ME!
0476: * @param b DOCUMENT ME!
0477: *
0478: * @return DOCUMENT ME!
0479: */
0480: public static boolean isMatch(AttributeType a, AttributeType b) {
0481: if (a == b) {
0482: return true;
0483: }
0484:
0485: if (b == null) {
0486: return false;
0487: }
0488:
0489: if (a == null) {
0490: return false;
0491: }
0492:
0493: if (a.equals(b)) {
0494: return true;
0495: }
0496:
0497: if (a.getName().equals(b.getName())
0498: && a.getClass().equals(b.getClass())) {
0499: return true;
0500: }
0501:
0502: return false;
0503: }
0504:
0505: /**
0506: * Creates duplicate of feature adjusted to the provided featureType.
0507: *
0508: * @param featureType FeatureType requested
0509: * @param feature Origional Feature from DataStore
0510: *
0511: * @return An instance of featureType based on feature
0512: *
0513: * @throws IllegalAttributeException If opperation could not be performed
0514: */
0515: public static Feature reType(FeatureType featureType,
0516: Feature feature) throws IllegalAttributeException {
0517: FeatureType origional = feature.getFeatureType();
0518:
0519: if (featureType.equals(origional)) {
0520: return featureType.duplicate(feature);
0521: }
0522:
0523: String id = feature.getID();
0524: int numAtts = featureType.getAttributeCount();
0525: Object[] attributes = new Object[numAtts];
0526: String xpath;
0527:
0528: for (int i = 0; i < numAtts; i++) {
0529: AttributeType curAttType = featureType.getAttributeType(i);
0530: xpath = curAttType.getName();
0531: attributes[i] = curAttType.duplicate(feature
0532: .getAttribute(xpath));
0533: }
0534:
0535: return featureType.create(attributes, id);
0536: }
0537:
0538: /**
0539: * Constructs an empty feature to use as a Template for new content.
0540: *
0541: * <p>
0542: * We may move this functionality to FeatureType.create( null )?
0543: * </p>
0544: *
0545: * @param featureType Type of feature we wish to create
0546: *
0547: * @return A new Feature of type featureType
0548: *
0549: * @throws IllegalAttributeException if we could not create featureType
0550: * instance with acceptable default values
0551: */
0552: public static Feature template(FeatureType featureType)
0553: throws IllegalAttributeException {
0554: return featureType.create(defaultValues(featureType));
0555: }
0556:
0557: /**
0558: * DOCUMENT ME!
0559: *
0560: * @param featureType DOCUMENT ME!
0561: * @param featureID DOCUMENT ME!
0562: *
0563: * @return DOCUMENT ME!
0564: *
0565: * @throws IllegalAttributeException DOCUMENT ME!
0566: */
0567: public static Feature template(FeatureType featureType,
0568: String featureID) throws IllegalAttributeException {
0569: return featureType
0570: .create(defaultValues(featureType), featureID);
0571: }
0572:
0573: /**
0574: * DOCUMENT ME!
0575: *
0576: * @param featureType DOCUMENT ME!
0577: *
0578: * @return DOCUMENT ME!
0579: *
0580: * @throws IllegalAttributeException DOCUMENT ME!
0581: */
0582: public static Object[] defaultValues(FeatureType featureType)
0583: throws IllegalAttributeException {
0584: return defaultValues(featureType, null);
0585: }
0586:
0587: /**
0588: * DOCUMENT ME!
0589: *
0590: * @param featureType DOCUMENT ME!
0591: * @param atts DOCUMENT ME!
0592: *
0593: * @return DOCUMENT ME!
0594: *
0595: * @throws IllegalAttributeException DOCUMENT ME!
0596: */
0597: public static Feature template(FeatureType featureType,
0598: Object[] atts) throws IllegalAttributeException {
0599: return featureType.create(defaultValues(featureType, atts));
0600: }
0601:
0602: /**
0603: * DOCUMENT ME!
0604: *
0605: * @param featureType DOCUMENT ME!
0606: * @param featureID DOCUMENT ME!
0607: * @param atts DOCUMENT ME!
0608: *
0609: * @return DOCUMENT ME!
0610: *
0611: * @throws IllegalAttributeException DOCUMENT ME!
0612: */
0613: public static Feature template(FeatureType featureType,
0614: String featureID, Object[] atts)
0615: throws IllegalAttributeException {
0616: return featureType.create(defaultValues(featureType, atts),
0617: featureID);
0618: }
0619:
0620: /**
0621: * DOCUMENT ME!
0622: *
0623: * @param featureType DOCUMENT ME!
0624: * @param values DOCUMENT ME!
0625: *
0626: * @return DOCUMENT ME!
0627: *
0628: * @throws IllegalAttributeException DOCUMENT ME!
0629: * @throws ArrayIndexOutOfBoundsException DOCUMENT ME!
0630: */
0631: public static Object[] defaultValues(FeatureType featureType,
0632: Object[] values) throws IllegalAttributeException {
0633: if (values == null) {
0634: values = new Object[featureType.getAttributeCount()];
0635: } else if (values.length != featureType.getAttributeCount()) {
0636: throw new ArrayIndexOutOfBoundsException("values");
0637: }
0638:
0639: for (int i = 0; i < featureType.getAttributeCount(); i++) {
0640: values[i] = defaultValue(featureType.getAttributeType(i));
0641: }
0642:
0643: return values;
0644: }
0645:
0646: /**
0647: * Provides a defautlValue for attributeType.
0648: *
0649: * <p>
0650: * Will return null if attributeType isNillable(), or attempt to use
0651: * Reflection, or attributeType.parse( null )
0652: * </p>
0653: *
0654: * @param attributeType
0655: *
0656: * @return null for nillable attributeType, attempt at reflection
0657: *
0658: * @throws IllegalAttributeException If value cannot be constructed for
0659: * attribtueType
0660: */
0661: public static Object defaultValue(AttributeType attributeType)
0662: throws IllegalAttributeException {
0663: Object value = attributeType.createDefaultValue();
0664:
0665: if (value == null && !attributeType.isNillable()) {
0666: throw new IllegalAttributeException(
0667: "Got null default value for non-null type.");
0668: }
0669: return value;
0670: }
0671:
0672: /**
0673: * Returns a non-null default value for the class that is passed in. This is a helper class an can't create a
0674: * default class for any type but it does support:
0675: * <ul>
0676: * <li>String</li>
0677: * <li>Object - will return empty string</li>
0678: * <li>Number</li>
0679: * <li>Character</li>
0680: * <li>JTS Geometries</li>
0681: * </ul>
0682: *
0683: *
0684: * @param type
0685: * @return
0686: */
0687: public static Object defaultValue(Class type) {
0688: if (type == String.class || type == Object.class) {
0689: return "";
0690: }
0691: if (type == Integer.class) {
0692: return new Integer(0);
0693: }
0694: if (type == Double.class) {
0695: return new Double(0);
0696: }
0697: if (type == Long.class) {
0698: return new Long(0);
0699: }
0700: if (type == Short.class) {
0701: return new Short((short) 0);
0702: }
0703: if (type == Float.class) {
0704: return new Float(0.0f);
0705: }
0706: if (type == Character.class) {
0707: return new Character(' ');
0708: }
0709:
0710: GeometryFactory fac = new GeometryFactory();
0711: Coordinate coordinate = new Coordinate(0, 0);
0712: Point point = fac.createPoint(coordinate);
0713:
0714: if (type == Point.class) {
0715: return point;
0716: }
0717: if (type == MultiPoint.class) {
0718: return fac.createMultiPoint(new Point[] { point });
0719: }
0720: if (type == LineString.class) {
0721: return fac.createLineString(new Coordinate[] { coordinate,
0722: coordinate, coordinate, coordinate });
0723: }
0724: LinearRing linearRing = fac.createLinearRing(new Coordinate[] {
0725: coordinate, coordinate, coordinate, coordinate });
0726: if (type == LinearRing.class) {
0727: return linearRing;
0728: }
0729: if (type == MultiLineString.class) {
0730: return fac
0731: .createMultiLineString(new LineString[] { linearRing });
0732: }
0733: Polygon polygon = fac.createPolygon(linearRing,
0734: new LinearRing[0]);
0735: if (type == Polygon.class) {
0736: return polygon;
0737: }
0738: if (type == MultiPolygon.class) {
0739: return fac.createMultiPolygon(new Polygon[] { polygon });
0740: }
0741:
0742: throw new IllegalArgumentException(type
0743: + " is not supported by this method");
0744: }
0745:
0746: /**
0747: * Creates a FeatureReader for testing.
0748: *
0749: * @param features Array of features
0750: *
0751: * @return FeatureReader spaning provided feature array
0752: *
0753: * @throws IOException If provided features Are null or empty
0754: * @throws NoSuchElementException DOCUMENT ME!
0755: */
0756: public static FeatureReader reader(final Feature[] features)
0757: throws IOException {
0758: if ((features == null) || (features.length == 0)) {
0759: throw new IOException("Provided features where empty");
0760: }
0761:
0762: return new FeatureReader() {
0763: Feature[] array = features;
0764: int offset = -1;
0765:
0766: public FeatureType getFeatureType() {
0767: return features[0].getFeatureType();
0768: }
0769:
0770: public Feature next() {
0771: if (!hasNext()) {
0772: throw new NoSuchElementException("No more features");
0773: }
0774:
0775: return array[++offset];
0776: }
0777:
0778: public boolean hasNext() {
0779: return (array != null) && (offset < (array.length - 1));
0780: }
0781:
0782: public void close() {
0783: array = null;
0784: offset = -1;
0785: }
0786: };
0787: }
0788:
0789: /**
0790: * DOCUMENT ME!
0791: *
0792: * @param featureArray DOCUMENT ME!
0793: *
0794: * @return DOCUMENT ME!
0795: *
0796: * @throws IOException DOCUMENT ME!
0797: * @throws RuntimeException DOCUMENT ME!
0798: */
0799: public static FeatureSource source(final Feature[] featureArray) {
0800: final FeatureType featureType;
0801:
0802: if ((featureArray == null) || (featureArray.length == 0)) {
0803: featureType = DefaultFeatureType.EMPTY;
0804: } else {
0805: featureType = featureArray[0].getFeatureType();
0806: }
0807:
0808: DataStore arrayStore = new AbstractDataStore() {
0809: public String[] getTypeNames() {
0810: return new String[] { featureType.getTypeName() };
0811: }
0812:
0813: public FeatureType getSchema(String typeName)
0814: throws IOException {
0815: if ((typeName != null)
0816: && typeName.equals(featureType.getTypeName())) {
0817: return featureType;
0818: }
0819:
0820: throw new IOException(typeName + " not available");
0821: }
0822:
0823: protected FeatureReader getFeatureReader(String typeName)
0824: throws IOException {
0825: return reader(featureArray);
0826: }
0827: };
0828:
0829: try {
0830: return arrayStore.getFeatureSource(arrayStore
0831: .getTypeNames()[0]);
0832: } catch (IOException e) {
0833: throw new RuntimeException(
0834: "Something is wrong with the geotools code, "
0835: + "this exception should not happen", e);
0836: }
0837: }
0838:
0839: /**
0840: * DOCUMENT ME!
0841: *
0842: * @param collection DOCUMENT ME!
0843: *
0844: * @return DOCUMENT ME!
0845: *
0846: * @throws NullPointerException DOCUMENT ME!
0847: * @throws RuntimeException DOCUMENT ME!
0848: */
0849: public static FeatureSource source(
0850: final FeatureCollection collection) {
0851: if (collection == null) {
0852: throw new NullPointerException();
0853: }
0854:
0855: DataStore store = new CollectionDataStore(collection);
0856:
0857: try {
0858: return store.getFeatureSource(store.getTypeNames()[0]);
0859: } catch (IOException e) {
0860: throw new RuntimeException(
0861: "Something is wrong with the geotools code, "
0862: + "this exception should not happen", e);
0863: }
0864: }
0865:
0866: public static FeatureCollection results(Feature[] featureArray) {
0867: return results(collection(featureArray));
0868: }
0869:
0870: /**
0871: * Returns collection if non empty.
0872: *
0873: * @param collection
0874: *
0875: * @return provided collection
0876: *
0877: * @throws IOException Raised if collection was empty
0878: */
0879: public static FeatureCollection results(
0880: final FeatureCollection collection) {
0881: if (collection.size() == 0) {
0882: //throw new IOException("Provided collection was empty");
0883: }
0884: return collection;
0885: }
0886:
0887: /**
0888: * DOCUMENT ME!
0889: *
0890: * @param collection DOCUMENT ME!
0891: *
0892: * @return DOCUMENT ME!
0893: *
0894: * @throws IOException DOCUMENT ME!
0895: */
0896: public static FeatureReader reader(Collection collection)
0897: throws IOException {
0898: return reader((Feature[]) collection
0899: .toArray(new Feature[collection.size()]));
0900: }
0901:
0902: /**
0903: * Copies the provided features into a FeatureCollection.
0904: * <p>
0905: * Often used when gathering features for FeatureStore:<pre><code>
0906: * featureStore.addFeatures( DataUtilities.collection(array));
0907: * </code></pre>
0908: *
0909: * @param features Array of features
0910: * @return FeatureCollection
0911: */
0912: public static FeatureCollection collection(Feature[] features) {
0913: FeatureCollection collection = FeatureCollections
0914: .newCollection();
0915: final int length = features.length;
0916: for (int i = 0; i < length; i++) {
0917: collection.add(features[i]);
0918: }
0919: return collection;
0920: }
0921:
0922: /**
0923: * Copies the provided features into a FeatureCollection.
0924: * <p>
0925: * Often used when gathering features for FeatureStore:<pre><code>
0926: * featureStore.addFeatures( DataUtilities.collection(feature));
0927: * </code></pre>
0928: *
0929: * @param features Array of features
0930: * @return FeatureCollection
0931: */
0932: public static FeatureCollection collection(Feature feature) {
0933: FeatureCollection collection = FeatureCollections
0934: .newCollection();
0935: collection.add(feature);
0936: return collection;
0937: }
0938:
0939: /**
0940: * Copies the provided reader into a FeatureCollection, reader will be closed.
0941: * <p>
0942: * Often used when gathering features for FeatureStore:<pre><code>
0943: * featureStore.addFeatures( DataUtilities.collection(reader));
0944: * </code></pre>
0945: *
0946: * @param features Array of features
0947: * @return FeatureCollection
0948: */
0949: public static FeatureCollection collection(FeatureReader reader)
0950: throws IOException {
0951: FeatureCollection collection = FeatureCollections
0952: .newCollection();
0953: try {
0954: while (reader.hasNext()) {
0955: try {
0956: collection.add(reader.next());
0957: } catch (NoSuchElementException e) {
0958: throw (IOException) new IOException("EOF")
0959: .initCause(e);
0960: } catch (IllegalAttributeException e) {
0961: throw (IOException) new IOException().initCause(e);
0962: }
0963: }
0964: } finally {
0965: reader.close();
0966: }
0967: return collection;
0968: }
0969:
0970: /**
0971: * Copies the provided reader into a FeatureCollection, reader will be closed.
0972: * <p>
0973: * Often used when gathering features for FeatureStore:<pre><code>
0974: * featureStore.addFeatures( DataUtilities.collection(reader));
0975: * </code></pre>
0976: *
0977: * @param features Array of features
0978: * @return FeatureCollection
0979: */
0980: public static FeatureCollection collection(FeatureIterator reader)
0981: throws IOException {
0982: FeatureCollection collection = FeatureCollections
0983: .newCollection();
0984: try {
0985: while (reader.hasNext()) {
0986: try {
0987: collection.add(reader.next());
0988: } catch (NoSuchElementException e) {
0989: throw (IOException) new IOException("EOF")
0990: .initCause(e);
0991: }
0992: }
0993: } finally {
0994: reader.close();
0995: }
0996: return collection;
0997: }
0998:
0999: /**
1000: * DOCUMENT ME!
1001: *
1002: * @param att DOCUMENT ME!
1003: * @param otherAtt DOCUMENT ME!
1004: *
1005: * @return DOCUMENT ME!
1006: */
1007: public static boolean attributesEqual(Object att, Object otherAtt) {
1008: if (att == null) {
1009: if (otherAtt != null) {
1010: return false;
1011: }
1012: } else {
1013: if (!att.equals(otherAtt)) {
1014: if (att instanceof Geometry
1015: && otherAtt instanceof Geometry) {
1016: // we need to special case Geometry
1017: // as JTS is broken
1018: // Geometry.equals( Object ) and Geometry.equals( Geometry )
1019: // are different
1020: // (We should fold this knowledge into AttributeType...)
1021: //
1022: if (!((Geometry) att).equals((Geometry) otherAtt)) {
1023: return false;
1024: }
1025: } else {
1026: return false;
1027: }
1028: }
1029: }
1030:
1031: return true;
1032: }
1033:
1034: /**
1035: * Create a derived FeatureType
1036: *
1037: * <p></p>
1038: *
1039: * @param featureType
1040: * @param properties - if null, every property of the feature type in input will be used
1041: * @param override
1042: *
1043: *
1044: * @throws SchemaException
1045: */
1046: public static FeatureType createSubType(FeatureType featureType,
1047: String[] properties, CoordinateReferenceSystem override)
1048: throws SchemaException {
1049: return createSubType(featureType, properties, override,
1050: featureType.getTypeName(), featureType.getNamespace());
1051: }
1052:
1053: public static FeatureType createSubType(FeatureType featureType,
1054: String[] properties, CoordinateReferenceSystem override,
1055: String typeName, URI namespace) throws SchemaException {
1056:
1057: if ((properties == null) && (override == null)) {
1058: return featureType;
1059: }
1060:
1061: if (properties == null) {
1062: properties = new String[featureType.getAttributeCount()];
1063: for (int i = 0; i < properties.length; i++) {
1064: properties[i] = featureType.getAttributeType(i)
1065: .getName();
1066: }
1067: }
1068:
1069: boolean same = featureType.getAttributeCount() == properties.length
1070: && featureType.getTypeName().equals(typeName)
1071: && featureType.getNamespace().equals(namespace);
1072:
1073: for (int i = 0; (i < featureType.getAttributeCount()) && same; i++) {
1074: AttributeType type = featureType.getAttributeType(i);
1075: same = type.getName().equals(properties[i])
1076: && (((override != null) && type instanceof GeometryAttributeType) ? assertEquals(
1077: override, ((GeometryAttributeType) type)
1078: .getCoordinateSystem())
1079: : true);
1080: }
1081:
1082: if (same) {
1083: return featureType;
1084: }
1085:
1086: AttributeType[] types = new AttributeType[properties.length];
1087:
1088: for (int i = 0; i < properties.length; i++) {
1089: types[i] = featureType.getAttributeType(properties[i]);
1090:
1091: if ((override != null)
1092: && types[i] instanceof GeometryAttributeType) {
1093: types[i] = new GeometricAttributeType(
1094: (GeometricAttributeType) types[i], override);
1095: }
1096: }
1097:
1098: if (typeName == null)
1099: typeName = featureType.getTypeName();
1100: if (namespace == null)
1101: namespace = featureType.getNamespace();
1102:
1103: return FeatureTypeFactory.newFeatureType(types, typeName,
1104: namespace);
1105: }
1106:
1107: private static boolean assertEquals(Object o1, Object o2) {
1108: return o1 == null && o2 == null ? true : (o1 != null ? o1
1109: .equals(o2) : false);
1110: }
1111:
1112: /**
1113: * DOCUMENT ME!
1114: *
1115: * @param featureType DOCUMENT ME!
1116: * @param properties DOCUMENT ME!
1117: *
1118: * @return DOCUMENT ME!
1119: *
1120: * @throws SchemaException DOCUMENT ME!
1121: */
1122: public static FeatureType createSubType(FeatureType featureType,
1123: String[] properties) throws SchemaException {
1124: if (properties == null) {
1125: return featureType;
1126: }
1127:
1128: boolean same = featureType.getAttributeCount() == properties.length;
1129:
1130: for (int i = 0; (i < featureType.getAttributeCount()) && same; i++) {
1131: same = featureType.getAttributeType(i).getName().equals(
1132: properties[i]);
1133: }
1134:
1135: if (same) {
1136: return featureType;
1137: }
1138:
1139: AttributeType[] types = new AttributeType[properties.length];
1140:
1141: for (int i = 0; i < properties.length; i++) {
1142: types[i] = featureType.getAttributeType(properties[i]);
1143: }
1144: return FeatureTypeFactory.newFeatureType(types, featureType
1145: .getTypeName(), featureType.getNamespace());
1146: }
1147:
1148: /**
1149: * Utility method for FeatureType construction.
1150: *
1151: * <p>
1152: * Will parse a String of the form: <i>"name:Type,name2:Type2,..."</i>
1153: * </p>
1154: *
1155: * <p>
1156: * Where <i>Type</i> is defined by createAttribute.
1157: * </p>
1158: *
1159: * <p>
1160: * You may indicate the default Geometry with an astrix: "*geom:Geometry".
1161: * </p>
1162: *
1163: * <p>
1164: * Example:<code>name:"",age:0,geom:Geometry,centroid:Point,url:java.io.URL"</code>
1165: * </p>
1166: *
1167: * @param identification identification of FeatureType:
1168: * (<i>namesapce</i>).<i>typeName</i>
1169: * @param typeSpec Specification for FeatureType
1170: *
1171: *
1172: * @throws SchemaException
1173: */
1174: public static FeatureType createType(String identification,
1175: String typeSpec) throws SchemaException {
1176: int split = identification.lastIndexOf('.');
1177: String namespace = (split == -1) ? null : identification
1178: .substring(0, split);
1179: String typeName = (split == -1) ? identification
1180: : identification.substring(split + 1);
1181:
1182: FeatureTypeFactory typeFactory = FeatureTypeFactory
1183: .newInstance(typeName);
1184: try {
1185: if (namespace != null) {
1186: typeFactory.setNamespace(new URI(namespace));
1187: }
1188: } catch (URISyntaxException badNamespace) {
1189: throw new SchemaException(badNamespace);
1190: }
1191: typeFactory.setName(typeName);
1192:
1193: String[] types = typeSpec.split(",");
1194: int geometryIndex = -1; // records * specified goemetry
1195: AttributeType attributeType;
1196: GeometryAttributeType geometryAttribute = null; // records guess
1197:
1198: for (int i = 0; i < types.length; i++) {
1199: if (types[i].startsWith("*")) {
1200: types[i] = types[i].substring(1);
1201: geometryIndex = i;
1202: }
1203:
1204: attributeType = createAttribute(types[i]);
1205: typeFactory.addType(attributeType);
1206:
1207: if ((geometryAttribute == null)
1208: && attributeType instanceof GeometryAttributeType) {
1209: if (geometryIndex == -1) {
1210: geometryAttribute = (GeometryAttributeType) attributeType;
1211: } else if (geometryIndex == i) {
1212: geometryAttribute = (GeometryAttributeType) attributeType;
1213: }
1214: }
1215: }
1216:
1217: if (geometryAttribute != null) {
1218: typeFactory.setDefaultGeometry(geometryAttribute);
1219: }
1220:
1221: return typeFactory.getFeatureType();
1222: }
1223:
1224: /**
1225: * DOCUMENT ME!
1226: *
1227: * @param type DOCUMENT ME!
1228: * @param fid DOCUMENT ME!
1229: * @param text DOCUMENT ME!
1230: *
1231: * @return DOCUMENT ME!
1232: *
1233: * @throws IllegalAttributeException DOCUMENT ME!
1234: */
1235: public static Feature parse(FeatureType type, String fid,
1236: String[] text) throws IllegalAttributeException {
1237: Object[] attributes = new Object[text.length];
1238:
1239: for (int i = 0; i < text.length; i++) {
1240: attributes[i] = type.getAttributeType(i).parse(text[i]);
1241: }
1242:
1243: return type.create(attributes, fid);
1244: }
1245:
1246: /**
1247: * Record typeSpec for the provided featureType
1248: *
1249: * @param featureType DOCUMENT ME!
1250: *
1251: * @return DOCUMENT ME!
1252: */
1253: public static String spec(FeatureType featureType) {
1254: AttributeType[] types = featureType.getAttributeTypes();
1255: StringBuffer buf = new StringBuffer();
1256:
1257: for (int i = 0; i < types.length; i++) {
1258: buf.append(types[i].getName());
1259: buf.append(":");
1260: buf.append(typeMap(types[i].getType()));
1261: if (types[i] instanceof GeometryAttributeType) {
1262: GeometryAttributeType gat = (GeometryAttributeType) types[i];
1263: if (gat.getCoordinateSystem() != null
1264: && gat.getCoordinateSystem().getIdentifiers() != null) {
1265: for (Iterator it = gat.getCoordinateSystem()
1266: .getIdentifiers().iterator(); it.hasNext();) {
1267: Identifier id = (Identifier) it.next();
1268:
1269: if ((id.getAuthority() != null)
1270: && id.getAuthority().getTitle().equals(
1271: Citations.EPSG.getTitle())) {
1272: buf.append(":srid=" + id.getCode());
1273: break;
1274: }
1275:
1276: }
1277: }
1278: }
1279:
1280: if (i < (types.length - 1)) {
1281: buf.append(",");
1282: }
1283: }
1284:
1285: return buf.toString();
1286: }
1287:
1288: static Class type(String typeName) throws ClassNotFoundException {
1289: if (typeMap.containsKey(typeName)) {
1290: return (Class) typeMap.get(typeName);
1291: }
1292:
1293: return Class.forName(typeName);
1294: }
1295:
1296: static String typeMap(Class type) {
1297: for (Iterator i = typeMap.entrySet().iterator(); i.hasNext();) {
1298: Map.Entry entry = (Entry) i.next();
1299:
1300: if (entry.getValue().equals(type)) {
1301: return (String) entry.getKey();
1302: }
1303: }
1304:
1305: return type.getName();
1306: }
1307:
1308: /**
1309: * Takes two {@link Query}objects and produce a new one by mixing the
1310: * restrictions of both of them.
1311: *
1312: * <p>
1313: * The policy to mix the queries components is the following:
1314: *
1315: * <ul>
1316: * <li>
1317: * typeName: type names MUST match (not checked if some or both queries
1318: * equals to <code>Query.ALL</code>)
1319: * </li>
1320: * <li>
1321: * handle: you must provide one since no sensible choice can be done
1322: * between the handles of both queries
1323: * </li>
1324: * <li>
1325: * maxFeatures: the lower of the two maxFeatures values will be used (most
1326: * restrictive)
1327: * </li>
1328: * <li>
1329: * attributeNames: the attributes of both queries will be joined in a
1330: * single set of attributes. IMPORTANT: only <b><i>explicitly</i></b>
1331: * requested attributes will be joint, so, if the method
1332: * <code>retrieveAllProperties()</code> of some of the queries returns
1333: * <code>true</code> it does not means that all the properties will be
1334: * joined. You must create the query with the names of the properties you
1335: * want to load.
1336: * </li>
1337: * <li>
1338: * filter: the filtets of both queries are or'ed
1339: * </li>
1340: * </ul>
1341: * </p>
1342: *
1343: * @param firstQuery Query against this DataStore
1344: * @param secondQuery DOCUMENT ME!
1345: * @param handle DOCUMENT ME!
1346: *
1347: * @return Query restricted to the limits of definitionQuery
1348: *
1349: * @throws NullPointerException if some of the queries is null
1350: * @throws IllegalArgumentException if the type names of both queries do
1351: * not match
1352: */
1353: public static Query mixQueries(Query firstQuery, Query secondQuery,
1354: String handle) {
1355: if ((firstQuery == null) || (secondQuery == null)) {
1356: throw new NullPointerException("got a null query argument");
1357: }
1358:
1359: if (firstQuery.equals(Query.ALL)) {
1360: return secondQuery;
1361: } else if (secondQuery.equals(Query.ALL)) {
1362: return firstQuery;
1363: }
1364:
1365: if ((firstQuery.getTypeName() != null)
1366: && (secondQuery.getTypeName() != null)) {
1367: if (!firstQuery.getTypeName().equals(
1368: secondQuery.getTypeName())) {
1369: String msg = "Type names do not match: "
1370: + firstQuery.getTypeName() + " != "
1371: + secondQuery.getTypeName();
1372: throw new IllegalArgumentException(msg);
1373: }
1374: }
1375:
1376: // mix versions, if possible
1377: String version;
1378: if (firstQuery.getVersion() != null) {
1379: if (secondQuery.getVersion() != null
1380: && !secondQuery.getVersion().equals(
1381: firstQuery.getVersion()))
1382: throw new IllegalArgumentException(
1383: "First and second query refer different versions");
1384: version = firstQuery.getVersion();
1385: } else {
1386: version = secondQuery.getVersion();
1387: }
1388:
1389: //none of the queries equals Query.ALL, mix them
1390: //use the more restrictive max features field
1391: int maxFeatures = Math.min(firstQuery.getMaxFeatures(),
1392: secondQuery.getMaxFeatures());
1393:
1394: //join attributes names
1395: String[] propNames = joinAttributes(firstQuery
1396: .getPropertyNames(), secondQuery.getPropertyNames());
1397:
1398: //join filters
1399: Filter filter = firstQuery.getFilter();
1400: Filter filter2 = secondQuery.getFilter();
1401:
1402: if ((filter == null) || filter.equals(Filter.INCLUDE)) {
1403: filter = filter2;
1404: } else if ((filter2 != null) && !filter2.equals(Filter.INCLUDE)) {
1405: filter = ff.and(filter, filter2);
1406: }
1407:
1408: //build the mixed query
1409: String typeName = firstQuery.getTypeName() != null ? firstQuery
1410: .getTypeName() : secondQuery.getTypeName();
1411:
1412: DefaultQuery mixed = new DefaultQuery(typeName, filter,
1413: maxFeatures, propNames, handle);
1414: mixed.setVersion(version);
1415: return mixed;
1416: }
1417:
1418: /**
1419: * Creates a set of attribute names from the two input lists of names,
1420: * maintaining the order of the first list and appending the non repeated
1421: * names of the second.
1422: * <p>
1423: * In the case where both lists are <code>null</code>, <code>null</code>
1424: * is returned.
1425: * </p>
1426: *
1427: * @param atts1 the first list of attribute names, who's order will be
1428: * maintained
1429: * @param atts2 the second list of attribute names, from wich the non
1430: * repeated names will be appended to the resulting list
1431: *
1432: * @return Set of attribute names from <code>atts1</code> and
1433: * <code>atts2</code>
1434: */
1435: private static String[] joinAttributes(String[] atts1,
1436: String[] atts2) {
1437: String[] propNames = null;
1438:
1439: if (atts1 == null && atts2 == null) {
1440: return null;
1441: }
1442:
1443: List atts = new LinkedList();
1444:
1445: if (atts1 != null) {
1446: atts.addAll(Arrays.asList(atts1));
1447: }
1448:
1449: if (atts2 != null) {
1450: for (int i = 0; i < atts2.length; i++) {
1451: if (!atts.contains(atts2[i])) {
1452: atts.add(atts2[i]);
1453: }
1454: }
1455: }
1456:
1457: propNames = new String[atts.size()];
1458: atts.toArray(propNames);
1459:
1460: return propNames;
1461: }
1462:
1463: /**
1464: * Returns AttributeType based on String specification (based on UML).
1465: *
1466: * <p>
1467: * Will parse a String of the form: <i>"name:Type:hint"</i>
1468: * </p>
1469: *
1470: * <p>
1471: * Where <i>Type</i> is:
1472: * </p>
1473: *
1474: * <ul>
1475: * <li>
1476: * 0,Interger,int: represents Interger
1477: * </li>
1478: * <li>
1479: * 0.0, Double, double: represents Double
1480: * </li>
1481: * <li>
1482: * "",String,string: represents String
1483: * </li>
1484: * <li>
1485: * Geometry: represents Geometry
1486: * </li>
1487: * <li>
1488: * <i>full.class.path</i>: represents java type
1489: * </li>
1490: * </ul>
1491: *
1492: * <p>
1493: * Where <i>hint</i> is "hint1;hint2;...;hintN", in which "hintN" is one
1494: * of:
1495: * <ul>
1496: * <li><code>nillable</code></li>
1497: * <li><code>srid=<#></code></li>
1498: * </ul>
1499: * </p>
1500: *
1501: * @param typeSpec
1502: *
1503: *
1504: * @throws SchemaException If typeSpect could not be interpreted
1505: */
1506: static AttributeType createAttribute(String typeSpec)
1507: throws SchemaException {
1508: int split = typeSpec.indexOf(":");
1509:
1510: String name;
1511: String type;
1512: String hint = null;
1513:
1514: if (split == -1) {
1515: name = typeSpec;
1516: type = "String";
1517: } else {
1518: name = typeSpec.substring(0, split);
1519:
1520: int split2 = typeSpec.indexOf(":", split + 1);
1521:
1522: if (split2 == -1) {
1523: type = typeSpec.substring(split + 1);
1524: } else {
1525: type = typeSpec.substring(split + 1, split2);
1526: hint = typeSpec.substring(split2 + 1);
1527: }
1528: }
1529:
1530: try {
1531: boolean nillable = true;
1532: CoordinateReferenceSystem crs = null;
1533:
1534: if (hint != null) {
1535: StringTokenizer st = new StringTokenizer(hint, ";");
1536: while (st.hasMoreTokens()) {
1537: String h = st.nextToken();
1538: h = h.trim();
1539:
1540: //nillable?
1541: //JD: i am pretty sure this hint is useless since the
1542: // default is to make attributes nillable
1543: if (h.equals("nillable")) {
1544: nillable = true;
1545: }
1546: //spatial reference identieger?
1547: if (h.startsWith("srid=")) {
1548: String srid = h.split("=")[1];
1549: Integer.parseInt(srid);
1550: try {
1551: crs = CRS.decode("EPSG:" + srid);
1552: } catch (Exception e) {
1553: String msg = "Error decoding srs: " + srid;
1554: throw new SchemaException(msg, e);
1555: }
1556: }
1557: }
1558: }
1559:
1560: return AttributeTypeFactory.newAttributeType(name,
1561: type(type), nillable, Integer.MAX_VALUE, null, crs);
1562: } catch (ClassNotFoundException e) {
1563: throw new SchemaException("Could not type " + name + " as:"
1564: + type);
1565: }
1566: }
1567:
1568: // /**
1569: // * A quick and dirty FilterVisitor.
1570: // *
1571: // * <p>
1572: // * This is useful when creating FilterVisitors for use with traverseDepth(
1573: // * Filter, FilterVisitor ) method.
1574: // * </p>
1575: // *
1576: // * <p>
1577: // * visit( Filter ) and visit( Expression ) will pass their arguments off to
1578: // * more specialized functions.
1579: // * </p>
1580: // * @deprecated TODO: Traversal
1581: // */
1582: // abstract static class AbstractFilterVisitor implements FilterVisitor {
1583: // /**
1584: // * DOCUMENT ME!
1585: // *
1586: // * @param filter DOCUMENT ME!
1587: // */
1588: // public void visit(Filter filter) {
1589: // if (filter instanceof BetweenFilter) {
1590: // visit((BetweenFilter) filter);
1591: // } else if (filter instanceof CompareFilter) {
1592: // visit((CompareFilter) filter);
1593: // } else if (filter instanceof GeometryFilter) {
1594: // visit((GeometryFilter) filter);
1595: // } else if (filter instanceof LikeFilter) {
1596: // visit((LikeFilter) filter);
1597: // } else if (filter instanceof LogicFilter) {
1598: // visit((LogicFilter) filter);
1599: // } else if (filter instanceof NullFilter) {
1600: // visit((NullFilter) filter);
1601: // } else if (filter instanceof FidFilter) {
1602: // visit((FidFilter) filter);
1603: // }
1604: // }
1605: //
1606: // /**
1607: // * DOCUMENT ME!
1608: // *
1609: // * @param betweenFilter DOCUMENT ME!
1610: // */
1611: // public void visit(BetweenFilter betweenFilter) {
1612: // // DOCUMENT ME!
1613: // }
1614: //
1615: // /**
1616: // * DOCUMENT ME!
1617: // *
1618: // * @param comparefilter DOCUMENT ME!
1619: // */
1620: // public void visit(CompareFilter comparefilter) {
1621: // // DOCUMENT ME!
1622: // }
1623: //
1624: // /**
1625: // * DOCUMENT ME!
1626: // *
1627: // * @param geometryFilter DOCUMENT ME!
1628: // */
1629: // public void visit(GeometryFilter geometryFilter) {
1630: // // DOCUMENT ME!
1631: // }
1632: //
1633: // /**
1634: // * DOCUMENT ME!
1635: // *
1636: // * @param likeFilter DOCUMENT ME!
1637: // */
1638: // public void visit(LikeFilter likeFilter) {
1639: // // DOCUMENT ME!
1640: // }
1641: //
1642: // /**
1643: // * DOCUMENT ME!
1644: // *
1645: // * @param logicFilter DOCUMENT ME!
1646: // */
1647: // public void visit(LogicFilter logicFilter) {
1648: // // DOCUMENT ME!
1649: // }
1650: //
1651: // /**
1652: // * DOCUMENT ME!
1653: // *
1654: // * @param nullFilter DOCUMENT ME!
1655: // */
1656: // public void visit(NullFilter nullFilter) {
1657: // // DOCUMENT ME!
1658: // }
1659: //
1660: // /**
1661: // * DOCUMENT ME!
1662: // *
1663: // * @param fidFilter DOCUMENT ME!
1664: // */
1665: // public void visit(FidFilter fidFilter) {
1666: // // DOCUMENT ME!
1667: // }
1668: //
1669: // /**
1670: // * DOCUMENT ME!
1671: // *
1672: // * @param attributeExpression DOCUMENT ME!
1673: // */
1674: // public void visit(AttributeExpression attributeExpression) {
1675: // // DOCUMENT ME!
1676: // }
1677: //
1678: // /**
1679: // * DOCUMENT ME!
1680: // *
1681: // * @param expression DOCUMENT ME!
1682: // */
1683: // public void visit(Expression expression) {
1684: // if (expression instanceof AttributeExpression) {
1685: // visit((AttributeExpression) expression);
1686: // } else if (expression instanceof LiteralExpression) {
1687: // visit((LiteralExpression) expression);
1688: // } else if (expression instanceof MathExpression) {
1689: // visit((MathExpression) expression);
1690: // } else if (expression instanceof FunctionExpression) {
1691: // visit((FunctionExpression) expression);
1692: // }
1693: // }
1694: //
1695: // /**
1696: // * DOCUMENT ME!
1697: // *
1698: // * @param literalExpression DOCUMENT ME!
1699: // */
1700: // public void visit(LiteralExpression literalExpression) {
1701: // // DOCUMENT ME!
1702: // }
1703: //
1704: // /**
1705: // * DOCUMENT ME!
1706: // *
1707: // * @param mathExpression DOCUMENT ME!
1708: // */
1709: // public void visit(MathExpression mathExpression) {
1710: // // DOCUMENT ME!
1711: // }
1712: //
1713: // /**
1714: // * DOCUMENT ME!
1715: // *
1716: // * @param functionExpression DOCUMENT ME!
1717: // */
1718: // public void visit(FunctionExpression functionExpression) {
1719: // // DOCUMENT ME!
1720: // }
1721: // }
1722: //
1723: // /**
1724: // * Will traverse the entire data structure
1725: // *
1726: // * @deprecated Please use org.geotools.filter.visitor.AbstractFilterVisitor
1727: // */
1728: // abstract static class Traversal extends AbstractFilterVisitor {
1729: // abstract void traverse(Filter filter);
1730: //
1731: // abstract void traverse(Expression expression);
1732: //
1733: // /**
1734: // * DOCUMENT ME!
1735: // *
1736: // * @param betweenFilter DOCUMENT ME!
1737: // */
1738: // public void visit(BetweenFilter betweenFilter) {
1739: // traverse(betweenFilter.getLeftValue());
1740: // visit(betweenFilter.getLeftValue());
1741: //
1742: // traverse(betweenFilter.getMiddleValue());
1743: // visit(betweenFilter.getMiddleValue());
1744: //
1745: // traverse(betweenFilter.getRightValue());
1746: // visit(betweenFilter.getRightValue());
1747: // }
1748: //
1749: // /**
1750: // * DOCUMENT ME!
1751: // *
1752: // * @param compareFilter DOCUMENT ME!
1753: // */
1754: // public void visit(CompareFilter compareFilter) {
1755: // traverse(compareFilter.getLeftValue());
1756: // visit(compareFilter.getLeftValue());
1757: //
1758: // traverse(compareFilter.getRightValue());
1759: // visit(compareFilter.getRightValue());
1760: // }
1761: //
1762: // /**
1763: // * DOCUMENT ME!
1764: // *
1765: // * @param geometryFilter DOCUMENT ME!
1766: // */
1767: // public void visit(GeometryFilter geometryFilter) {
1768: // traverse(geometryFilter.getLeftGeometry());
1769: // visit(geometryFilter.getLeftGeometry());
1770: //
1771: // traverse(geometryFilter.getRightGeometry());
1772: // visit(geometryFilter.getRightGeometry());
1773: // }
1774: //
1775: // /**
1776: // * DOCUMENT ME!
1777: // *
1778: // * @param likeFilter DOCUMENT ME!
1779: // */
1780: // public void visit(LikeFilter likeFilter) {
1781: // traverse(likeFilter.getValue());
1782: // visit(likeFilter.getValue());
1783: // }
1784: //
1785: // /**
1786: // * DOCUMENT ME!
1787: // *
1788: // * @param logicFilter DOCUMENT ME!
1789: // */
1790: // public void visit(LogicFilter logicFilter) {
1791: // for (Iterator i = logicFilter.getFilterIterator(); i.hasNext();) {
1792: // // GR: LogicFilters are the only ones whose members are Filters
1793: // // instead of Expressions, so it was causing ClassCastExceptions
1794: // Filter f = (Filter) i.next();
1795: // traverse(f);
1796: // visit((org.geotools.filter.Filter) f);
1797: // }
1798: // }
1799: //
1800: // /**
1801: // * DOCUMENT ME!
1802: // *
1803: // * @param nullFilter DOCUMENT ME!
1804: // */
1805: // public void visit(NullFilter nullFilter) {
1806: // traverse(nullFilter.getNullCheckValue());
1807: // visit(nullFilter.getNullCheckValue());
1808: // }
1809: //
1810: // /**
1811: // * DOCUMENT ME!
1812: // *
1813: // * @param mathExpression DOCUMENT ME!
1814: // */
1815: // public void visit(MathExpression mathExpression) {
1816: // traverse(mathExpression.getLeftValue());
1817: // visit(mathExpression.getLeftValue());
1818: //
1819: // traverse(mathExpression.getRightValue());
1820: // visit(mathExpression.getRightValue());
1821: // }
1822: //
1823: // /**
1824: // * DOCUMENT ME!
1825: // *
1826: // * @param functionExpression DOCUMENT ME!
1827: // */
1828: // public void visit(FunctionExpression functionExpression) {
1829: // Expression[] args = functionExpression.getArgs();
1830: //
1831: // for (int i = 0; i < args.length; i++) {
1832: // traverse(args[i]);
1833: // visit(args[i]);
1834: // }
1835: // }
1836: // }
1837: //
1838:
1839: /**
1840: * Will traverse the entire data structure
1841: */
1842: abstract static class Traversal extends DefaultFilterVisitor {
1843: abstract void traverse(Filter filter);
1844:
1845: abstract void traverse(Expression expression);
1846:
1847: public Object visit(ExcludeFilter filter, Object data) {
1848: traverse(filter);
1849: return super .visit(filter, data);
1850: }
1851:
1852: public Object visit(IncludeFilter filter, Object data) {
1853: traverse(filter);
1854: return super .visit(filter, data);
1855: }
1856:
1857: public Object visit(And filter, Object data) {
1858: traverse(filter);
1859: return super .visit(filter, data);
1860: }
1861:
1862: public Object visit(Id filter, Object data) {
1863: traverse(filter);
1864: return super .visit(filter, data);
1865: }
1866:
1867: public Object visit(Not filter, Object data) {
1868: traverse(filter);
1869: return super .visit(filter, data);
1870: }
1871:
1872: public Object visit(Or filter, Object data) {
1873: traverse(filter);
1874: return super .visit(filter, data);
1875: }
1876:
1877: public Object visit(PropertyIsBetween filter, Object data) {
1878: traverse(filter);
1879: return super .visit(filter, data);
1880: }
1881:
1882: public Object visit(PropertyIsEqualTo filter, Object data) {
1883: traverse(filter);
1884: return super .visit(filter, data);
1885: }
1886:
1887: public Object visit(PropertyIsNotEqualTo filter, Object data) {
1888: traverse(filter);
1889: return super .visit(filter, data);
1890: }
1891:
1892: public Object visit(PropertyIsGreaterThan filter, Object data) {
1893: traverse(filter);
1894: return super .visit(filter, data);
1895: }
1896:
1897: public Object visit(PropertyIsGreaterThanOrEqualTo filter,
1898: Object data) {
1899: traverse(filter);
1900: return super .visit(filter, data);
1901: }
1902:
1903: public Object visit(PropertyIsLessThan filter, Object data) {
1904: traverse(filter);
1905: return super .visit(filter, data);
1906: }
1907:
1908: public Object visit(PropertyIsLessThanOrEqualTo filter,
1909: Object data) {
1910: traverse(filter);
1911: return super .visit(filter, data);
1912: }
1913:
1914: public Object visit(PropertyIsLike filter, Object data) {
1915: traverse(filter);
1916: return super .visit(filter, data);
1917: }
1918:
1919: public Object visit(PropertyIsNull filter, Object data) {
1920: traverse(filter);
1921: return super .visit(filter, data);
1922: }
1923:
1924: public Object visit(BBOX filter, Object data) {
1925: traverse(filter);
1926: return super .visit(filter, data);
1927: }
1928:
1929: public Object visit(Beyond filter, Object data) {
1930: traverse(filter);
1931: return super .visit(filter, data);
1932: }
1933:
1934: public Object visit(Contains filter, Object data) {
1935: traverse(filter);
1936: return super .visit(filter, data);
1937: }
1938:
1939: public Object visit(Crosses filter, Object data) {
1940: traverse(filter);
1941: return super .visit(filter, data);
1942: }
1943:
1944: public Object visit(Disjoint filter, Object data) {
1945: traverse(filter);
1946: return super .visit(filter, data);
1947: }
1948:
1949: public Object visit(DWithin filter, Object data) {
1950: traverse(filter);
1951: return super .visit(filter, data);
1952: }
1953:
1954: public Object visit(Equals filter, Object data) {
1955: traverse(filter);
1956: return super .visit(filter, data);
1957: }
1958:
1959: public Object visit(Intersects filter, Object data) {
1960: traverse(filter);
1961: return super .visit(filter, data);
1962: }
1963:
1964: public Object visit(Overlaps filter, Object data) {
1965: traverse(filter);
1966: return super .visit(filter, data);
1967: }
1968:
1969: public Object visit(Touches filter, Object data) {
1970: traverse(filter);
1971: return super .visit(filter, data);
1972: }
1973:
1974: public Object visit(Within filter, Object data) {
1975: traverse(filter);
1976: return super .visit(filter, data);
1977: }
1978:
1979: public Object visitNullFilter(Object data) {
1980: return super .visitNullFilter(data);
1981: }
1982:
1983: public Object visit(NilExpression expr, Object data) {
1984: traverse(expr);
1985: return super .visit(expr, data);
1986: }
1987:
1988: public Object visit(Add expr, Object data) {
1989: traverse(expr);
1990: return super .visit(expr, data);
1991: }
1992:
1993: public Object visit(Divide expr, Object data) {
1994: traverse(expr);
1995: return super .visit(expr, data);
1996: }
1997:
1998: public Object visit(Function expr, Object data) {
1999: traverse(expr);
2000: return super .visit(expr, data);
2001: }
2002:
2003: public Object visit(Literal expr, Object data) {
2004: traverse(expr);
2005: return super .visit(expr, data);
2006: }
2007:
2008: public Object visit(Multiply expr, Object data) {
2009: traverse(expr);
2010: return super .visit(expr, data);
2011: }
2012:
2013: public Object visit(PropertyName expr, Object data) {
2014: traverse(expr);
2015: return super .visit(expr, data);
2016: }
2017:
2018: public Object visit(Subtract expr, Object data) {
2019: traverse(expr);
2020: return super .visit(expr, data);
2021: }
2022: }
2023:
2024: /**
2025: * Manually calculates the bounds of a feature collection.
2026: * @param collection
2027: * @return
2028: */
2029: public static Envelope bounds(FeatureCollection collection) {
2030: Iterator i = collection.iterator();
2031: try {
2032: Envelope bounds = new Envelope();
2033: if (!i.hasNext()) {
2034: bounds.setToNull();
2035: return bounds;
2036: }
2037:
2038: bounds.init(((Feature) i.next()).getBounds());
2039: return bounds;
2040: } finally {
2041: collection.close(i);
2042: }
2043: }
2044: }
|