[Schmitzm-commits] r1160 - in trunk: src/schmitzm/geotools/feature src/schmitzm/swing src/skrueger/geotools src/skrueger/geotools/io src_junit src_junit/org src_junit/org/geotools src_junit/org/geotools/data

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Fri Oct 22 23:35:32 CEST 2010


Author: alfonx
Date: 2010-10-22 23:35:30 +0200 (Fri, 22 Oct 2010)
New Revision: 1160

Added:
   trunk/src/skrueger/geotools/io/TwistedLatLonFeatureSource.java
   trunk/src_junit/org/
   trunk/src_junit/org/geotools/
   trunk/src_junit/org/geotools/data/
   trunk/src_junit/org/geotools/data/DataUtilities.java
Modified:
   trunk/src/schmitzm/geotools/feature/FeatureUtil.java
   trunk/src/schmitzm/swing/SwingUtil.java
   trunk/src/skrueger/geotools/StyledFS.java
Log:
Tweaking AS with WFS

Modified: trunk/src/schmitzm/geotools/feature/FeatureUtil.java
===================================================================
--- trunk/src/schmitzm/geotools/feature/FeatureUtil.java	2010-10-22 17:56:28 UTC (rev 1159)
+++ trunk/src/schmitzm/geotools/feature/FeatureUtil.java	2010-10-22 21:35:30 UTC (rev 1160)
@@ -92,6 +92,7 @@
 import org.geotools.styling.StyleBuilder;
 import org.geotools.styling.Symbolizer;
 import org.geotools.util.SimpleInternationalString;
+import org.jfree.util.Log;
 import org.opengis.coverage.grid.GridCoverageReader;
 import org.opengis.feature.IllegalAttributeException;
 import org.opengis.feature.simple.SimpleFeature;
@@ -107,7 +108,6 @@
 
 import schmitzm.geotools.FilterUtil;
 import schmitzm.geotools.GTUtil;
-import schmitzm.geotools.gui.GeoPositionLabel;
 import schmitzm.io.IOUtil;
 import schmitzm.lang.LangUtil;
 import schmitzm.lang.ResourceProvider;
@@ -320,7 +320,8 @@
 			return GeometryForm.POLYGON;
 		else if (com.vividsolutions.jts.geom.Geometry.class
 				.isAssignableFrom(geometryType)) {
-			// TODO This happens with some "special" WFS services and has to be ahndeletd much nicer
+			// TODO This happens with some "special" WFS services and has to be
+			// ahndeletd much nicer
 			return GeometryForm.POLYGON;
 		}
 
@@ -2032,11 +2033,17 @@
 			values = getDefaultAttributeValues(schema);
 
 		try {
-			
-			if (schema.getGeometryDescriptor().getType().isAbstract()) {
-				System.err.println("sdsdsds");
+
+			if (schema.getGeometryDescriptor().getType().getBinding() == Geometry.class
+					.getClass()) {
+				// When parsing GML it can be all mixed.
+				Log.info("This is "
+						+ schema.getGeometryDescriptor().getType().getBinding());
+				
+//		WOuld be cool, if we could set a default type here:		schema.getGeometryDescriptor().set...
+
 			}
-			
+
 			SimpleFeatureBuilder builder = new SimpleFeatureBuilder(schema);
 			sampleFeature = builder.buildFeature("createSampleFeature_"
 					+ new Random().nextInt(), values);

Modified: trunk/src/schmitzm/swing/SwingUtil.java
===================================================================
--- trunk/src/schmitzm/swing/SwingUtil.java	2010-10-22 17:56:28 UTC (rev 1159)
+++ trunk/src/schmitzm/swing/SwingUtil.java	2010-10-22 21:35:30 UTC (rev 1160)
@@ -78,7 +78,6 @@
 
 import schmitzm.lang.LangUtil;
 import schmitzm.lang.ResourceProvider;
-import skrueger.swing.AtlasDialog;
 
 /**
  * Diese Klasse beinhaltet statische Hilfsfunktionen fuer das Arbeiten mit

Modified: trunk/src/skrueger/geotools/StyledFS.java
===================================================================
--- trunk/src/skrueger/geotools/StyledFS.java	2010-10-22 17:56:28 UTC (rev 1159)
+++ trunk/src/skrueger/geotools/StyledFS.java	2010-10-22 21:35:30 UTC (rev 1160)
@@ -412,4 +412,8 @@
 		setDesc(new Translation(desc));
 	}
 
+	public void setCRS(CoordinateReferenceSystem crs2) {
+		crs=crs2;
+	}
+
 }

Added: trunk/src/skrueger/geotools/io/TwistedLatLonFeatureSource.java
===================================================================
--- trunk/src/skrueger/geotools/io/TwistedLatLonFeatureSource.java	2010-10-22 17:56:28 UTC (rev 1159)
+++ trunk/src/skrueger/geotools/io/TwistedLatLonFeatureSource.java	2010-10-22 21:35:30 UTC (rev 1160)
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Stefan A. Tzeggai.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Public License v2.0
+ * which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * 
+ * Contributors:
+ *     Stefan A. Tzeggai - initial API and implementation
+ ******************************************************************************/
+package skrueger.geotools.io;
+
+import java.io.IOException;
+import java.util.Set;
+
+import org.geotools.data.DataAccess;
+import org.geotools.data.FeatureListener;
+import org.geotools.data.FeatureSource;
+import org.geotools.data.Query;
+import org.geotools.data.QueryCapabilities;
+import org.geotools.data.ResourceInfo;
+import org.geotools.feature.FeatureCollection;
+import org.geotools.geometry.jts.ReferencedEnvelope;
+import org.opengis.feature.simple.SimpleFeature;
+import org.opengis.feature.simple.SimpleFeatureType;
+import org.opengis.feature.type.Name;
+import org.opengis.filter.Filter;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.crs.GeographicCRS;
+
+import com.vividsolutions.jts.geom.Envelope;
+
+public class TwistedLatLonFeatureSource implements
+		FeatureSource<SimpleFeatureType, SimpleFeature> {
+
+	private final FeatureSource<SimpleFeatureType, SimpleFeature> originaleFS;
+	private boolean twist = false;
+
+	public TwistedLatLonFeatureSource(
+			FeatureSource<SimpleFeatureType, SimpleFeature> originaleFS) {
+		this.originaleFS = originaleFS;
+
+		CoordinateReferenceSystem crs = originaleFS.getSchema()
+				.getCoordinateReferenceSystem();
+		if (crs instanceof GeographicCRS) {
+			System.out.println("CRS is GeographicCRS, twist it!");
+			setTwist(true);
+		}
+	}
+
+	@Override
+	public void addFeatureListener(FeatureListener listener) {
+		originaleFS.addFeatureListener(listener);
+	}
+
+	@Override
+	public ReferencedEnvelope getBounds() throws IOException {
+		if (isTwist()) {
+			Envelope oldEnv = originaleFS.getBounds();
+			return new ReferencedEnvelope(oldEnv.getMinY(), oldEnv.getMinX(),
+					oldEnv.getMaxY(), oldEnv.getMaxX(), getSchema()
+							.getCoordinateReferenceSystem());
+		} else
+			return originaleFS.getBounds();
+	}
+
+	@Override
+	public ReferencedEnvelope getBounds(Query query) throws IOException {
+		return null;
+	}
+
+	@Override
+	public int getCount(Query query) throws IOException {
+		return originaleFS.getCount(query);
+	}
+
+	@Override
+	public DataAccess<SimpleFeatureType, SimpleFeature> getDataStore() {
+		return originaleFS.getDataStore();
+	}
+
+	@Override
+	public FeatureCollection<SimpleFeatureType, SimpleFeature> getFeatures()
+			throws IOException {
+		return originaleFS.getFeatures();
+	}
+
+	@Override
+	public FeatureCollection<SimpleFeatureType, SimpleFeature> getFeatures(
+			Query query) throws IOException {
+		return originaleFS.getFeatures(query);
+	}
+
+	@Override
+	public FeatureCollection<SimpleFeatureType, SimpleFeature> getFeatures(
+			Filter filter) throws IOException {
+		return originaleFS.getFeatures(filter);
+	}
+
+	@Override
+	public QueryCapabilities getQueryCapabilities() {
+		return originaleFS.getQueryCapabilities();
+	}
+
+	@Override
+	public SimpleFeatureType getSchema() {
+		return originaleFS.getSchema();
+	}
+
+	@Override
+	public Set getSupportedHints() {
+		return originaleFS.getSupportedHints();
+	}
+
+	@Override
+	public void removeFeatureListener(FeatureListener listener) {
+		originaleFS.removeFeatureListener(listener);
+	}
+
+	@Override
+	public ResourceInfo getInfo() {
+		return originaleFS.getInfo();
+	}
+
+	@Override
+	public Name getName() {
+		return originaleFS.getName();
+	}
+
+	public void setTwist(boolean twist) {
+		this.twist = twist;
+	}
+
+	public boolean isTwist() {
+		return twist;
+	}
+
+}


Property changes on: trunk/src/skrueger/geotools/io/TwistedLatLonFeatureSource.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Id URL
Name: svn:eol-style
   + native

Added: trunk/src_junit/org/geotools/data/DataUtilities.java
===================================================================
--- trunk/src_junit/org/geotools/data/DataUtilities.java	2010-10-22 17:56:28 UTC (rev 1159)
+++ trunk/src_junit/org/geotools/data/DataUtilities.java	2010-10-22 21:35:30 UTC (rev 1160)
@@ -0,0 +1,2005 @@
+/*
+ *    GeoTools - The Open Source Java GIS Toolkit
+ *    http://geotools.org
+ * 
+ *    (C) 2003-2008, 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.data;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Array;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.commons.io.filefilter.IOFileFilter;
+import org.geotools.data.collection.CollectionDataStore;
+import org.geotools.factory.CommonFactoryFinder;
+import org.geotools.feature.AttributeTypeBuilder;
+import org.geotools.feature.DefaultFeatureCollection;
+import org.geotools.feature.FeatureCollection;
+import org.geotools.feature.FeatureCollections;
+import org.geotools.feature.FeatureIterator;
+import org.geotools.feature.FeatureTypes;
+import org.geotools.feature.IllegalAttributeException;
+import org.geotools.feature.NameImpl;
+import org.geotools.feature.SchemaException;
+import org.geotools.feature.simple.SimpleFeatureBuilder;
+import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
+import org.geotools.feature.type.AttributeDescriptorImpl;
+import org.geotools.feature.type.AttributeTypeImpl;
+import org.geotools.feature.type.GeometryDescriptorImpl;
+import org.geotools.feature.type.GeometryTypeImpl;
+import org.geotools.filter.FilterAttributeExtractor;
+import org.geotools.geometry.jts.ReferencedEnvelope;
+import org.geotools.metadata.iso.citation.Citations;
+import org.geotools.referencing.CRS;
+import org.geotools.resources.Utilities;
+import org.geotools.resources.i18n.ErrorKeys;
+import org.geotools.resources.i18n.Errors;
+import org.geotools.util.Converters;
+import org.opengis.coverage.grid.GridCoverage;
+import org.opengis.feature.Feature;
+import org.opengis.feature.FeatureVisitor;
+import org.opengis.feature.simple.SimpleFeature;
+import org.opengis.feature.simple.SimpleFeatureType;
+import org.opengis.feature.type.AttributeDescriptor;
+import org.opengis.feature.type.AttributeType;
+import org.opengis.feature.type.FeatureType;
+import org.opengis.feature.type.GeometryDescriptor;
+import org.opengis.feature.type.GeometryType;
+import org.opengis.feature.type.PropertyDescriptor;
+import org.opengis.filter.Filter;
+import org.opengis.filter.FilterFactory;
+import org.opengis.filter.expression.Expression;
+import org.opengis.referencing.ReferenceIdentifier;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Envelope;
+import com.vividsolutions.jts.geom.Geometry;
+import com.vividsolutions.jts.geom.GeometryCollection;
+import com.vividsolutions.jts.geom.GeometryFactory;
+import com.vividsolutions.jts.geom.LineString;
+import com.vividsolutions.jts.geom.LinearRing;
+import com.vividsolutions.jts.geom.MultiLineString;
+import com.vividsolutions.jts.geom.MultiPoint;
+import com.vividsolutions.jts.geom.MultiPolygon;
+import com.vividsolutions.jts.geom.Point;
+import com.vividsolutions.jts.geom.Polygon;
+
+/**
+ * Utility functions for use when implementing working with data classes.
+ * <p>
+ * TODO: Move FeatureType manipulation to feature package
+ * </p>
+ * @author Jody Garnett, Refractions Research
+ * @source $URL$
+ */
+public class DataUtilities {
+    
+    static Map<String,Class> typeMap = new HashMap<String,Class>();
+    static Map<Class,String> typeEncode = new HashMap<Class,String>();
+    
+    static FilterFactory ff = CommonFactoryFinder.getFilterFactory( null );
+    
+    static {
+        typeEncode.put( String.class, "String");
+        typeMap.put("String", String.class);
+        typeMap.put("string", String.class);
+        typeMap.put("\"\"", String.class);
+        
+        typeEncode.put( Integer.class, "Integer");        
+        typeMap.put("Integer", Integer.class);
+        typeMap.put("int", Integer.class);
+        typeMap.put("0", Integer.class);
+
+        typeEncode.put( Double.class, "Double");        
+        typeMap.put("Double", Double.class);
+        typeMap.put("double", Double.class);
+        typeMap.put("0.0", Double.class);
+
+        typeEncode.put( Float.class, "Float");        
+        typeMap.put("Float", Float.class);
+        typeMap.put("float", Float.class);
+        typeMap.put("0.0f", Float.class);
+
+        typeEncode.put( Boolean.class, "Boolean");        
+        typeMap.put("Boolean", Boolean.class);        
+        typeMap.put("true",Boolean.class);
+        typeMap.put("false",Boolean.class);
+        
+        typeEncode.put( Geometry.class, "Geometry");
+        typeMap.put("Geometry", Geometry.class);
+        
+        typeEncode.put( Point.class, "Point");        
+        typeMap.put("Point", Point.class);
+        
+        typeEncode.put( LineString.class, "LineString");
+        typeMap.put("LineString", LineString.class);
+        
+        typeEncode.put( Polygon.class, "Polygon");
+        typeMap.put("Polygon", Polygon.class);
+        
+        typeEncode.put( MultiPoint.class, "MultiPoint");
+        typeMap.put("MultiPoint", MultiPoint.class);
+        
+        typeEncode.put( MultiLineString.class, "MultiLineString");
+        typeMap.put("MultiLineString", MultiLineString.class);
+        
+        typeEncode.put( MultiPolygon.class, "MultiPolygon");
+        typeMap.put("MultiPolygon", MultiPolygon.class);
+        
+        typeEncode.put( GeometryCollection.class, "GeometryCollection");
+        typeMap.put("GeometryCollection", GeometryCollection.class);
+        
+        typeEncode.put( Date.class, "Date");
+        typeMap.put("Date",Date.class);
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @param featureType DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     */
+    public static String[] attributeNames(SimpleFeatureType featureType) {
+        String[] names = new String[featureType.getAttributeCount()];
+        final int count = featureType.getAttributeCount();
+        for (int i = 0; i < count; i++) {
+        	names[i] = featureType.getDescriptor(i).getLocalName();
+        }
+        
+        return names;
+    }
+    
+    /**
+     * A replacement for File.toURI().toURL().
+     * <p>
+     * The handling of file.toURL() is broken; the handling of file.toURI().toURL() is known
+     * to be broken on a few platforms like mac. We have the urlToFile( URL ) method that
+     * is able to untangle both these problems and we use it in the geotools library.
+     * <p>
+     * However occasionally we need to pick up a file and hand it to a third party library
+     * like EMF; this method performs a couple of sanity checks which we can use to prepare
+     * a good URL reference to a file in these situtations.
+     * 
+     * @param file
+     * @return URL
+     */
+    public static URL fileToURL(File file) {
+        try {
+            URL url = file.toURI().toURL();
+            String string = url.toExternalForm();
+            if( string.contains("+")){
+                // this represents an invalid URL created using either
+                // file.toURL(); or
+                // file.toURI().toURL() on a specific version of Java 5 on Mac
+                string = string.replace("+","%2B");
+            }
+            if( string.contains(" ")){
+                // this represents an invalid URL created using either
+                // file.toURL(); or
+                // file.toURI().toURL() on a specific version of Java 5 on Mac
+                string = string.replace(" ","%20");
+            }
+            return new URL( string );
+        } catch (MalformedURLException e) {
+            return null;
+        }
+    }
+    
+    /**
+     * Takes a URL and converts it to a File. The attempts to deal with 
+     * Windows UNC format specific problems, specifically files located
+     * on network shares and different drives.
+     * 
+     * If the URL.getAuthority() returns null or is empty, then only the
+     * url's path property is used to construct the file. Otherwise, the
+     * authority is prefixed before the path.
+     * 
+     * It is assumed that url.getProtocol returns "file".
+     * 
+     * Authority is the drive or network share the file is located on.
+     * Such as "C:", "E:", "\\fooServer"
+     * 
+     * @param url a URL object that uses protocol "file"
+     * @return a File that corresponds to the URL's location
+     */
+    public static File urlToFile(URL url) {
+        if( !"file".equals(url.getProtocol())){
+            return null; // not a File URL
+        }
+        String string = url.toExternalForm();
+        if( string.contains("+")){
+            // this represents an invalid URL created using either
+            // file.toURL(); or
+            // file.toURI().toURL() on a specific version of Java 5 on Mac
+            string = string.replace("+","%2B");
+        }
+        try {
+            string = URLDecoder.decode(string, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException("Could not decode the URL to UTF-8 format", e);
+        }
+        
+        String path3;
+
+        String simplePrefix = "file:/";
+        String standardPrefix = "file://";
+        String os = System.getProperty("os.name");
+        
+        if (os.toUpperCase().contains("WINDOWS") && string.startsWith(standardPrefix)) {
+        	// win32: host/share reference
+        	path3 = string.substring(standardPrefix.length()-2);
+        }
+        else if( string.startsWith(standardPrefix) ){
+            path3 = string.substring( standardPrefix.length() );
+        } else if( string.startsWith(simplePrefix)){
+            path3 = string.substring( simplePrefix.length()-1 );            
+        } else {
+            String auth = url.getAuthority();
+            String path2 = url.getPath().replace("%20", " ");
+            if (auth != null && !auth.equals("")) {
+                path3 = "//" + auth + path2;
+            } else {
+                path3 = path2;
+            }
+        }
+        
+        return new File(path3);
+    }
+
+
+    /**
+     * Traverses the filter and returns any encoutered property names.
+     * <p>
+     * The feautre type is supplied as contexts used to lookup expressions in cases where the 
+     * attributeName does not match the actual name of the type.
+     * </p>
+     */
+    public static String[] attributeNames( Filter filter, final SimpleFeatureType featureType ) {
+    	 if (filter == null) {
+             return new String[0];
+         }
+         FilterAttributeExtractor attExtractor = new FilterAttributeExtractor(featureType);
+         filter.accept(attExtractor, null);
+         String[] attributeNames = attExtractor.getAttributeNames();
+         return attributeNames;
+    }
+    
+    /**
+     * Traverses the filter and returns any encoutered property names.
+     * @deprecated use {@link #attributeNames(Filter, FeatureType)}/
+     */
+    public static String[] attributeNames(Filter filter) {
+       return attributeNames( filter, null );
+    }
+
+    /**
+     * Traverses the expression and returns any encoutered property names.
+     * <p>
+     * The feautre type is supplied as contexts used to lookup expressions in cases where the 
+     * attributeName does not match the actual name of the type.
+     * </p>
+     */
+    public static String[] attributeNames(Expression expression, final SimpleFeatureType featureType ) {
+    	 if (expression == null) {
+             return new String[0];
+         }
+         FilterAttributeExtractor attExtractor = new FilterAttributeExtractor(featureType);
+         expression.accept(attExtractor, null);
+         String[] attributeNames = attExtractor.getAttributeNames();
+         return attributeNames;
+    }
+    
+    /**
+     * Traverses the expression and returns any encoutered property names.
+     * @deprecated use {@link #attributeNames(Expression, FeatureType)}/
+     */
+    public static String[] attributeNames(Expression expression) {
+       return attributeNames( expression, null );
+    }
+
+    /**
+     * Compare operation for FeatureType.
+     * 
+     * <p>
+     * Results in:
+     * </p>
+     * 
+     * <ul>
+     * <li>
+     * 1: if typeA is a sub type/reorder/renamespace of typeB
+     * </li>
+     * <li>
+     * 0: if typeA and typeB are the same type
+     * </li>
+     * <li>
+     * -1: if typeA is not subtype of typeB
+     * </li>
+     * </ul>
+     * 
+     * <p>
+     * Comparison is based on AttributeTypes, an IOException is thrown if the
+     * AttributeTypes are not compatiable.
+     * </p>
+     * 
+     * <p>
+     * Namespace is not considered in this opperations. You may still need to
+     * reType to get the correct namesapce, or reorder.
+     * </p>
+     *
+     * @param typeA FeatureType beind compared
+     * @param typeB FeatureType being compared against
+     *
+     */
+    public static int compare(SimpleFeatureType typeA, SimpleFeatureType typeB) {
+        if (typeA == typeB) {
+            return 0;
+        }
+
+        if (typeA == null) {
+            return -1;  
+        }
+
+        if (typeB == null) {
+            return -1;
+        }
+
+        int countA = typeA.getAttributeCount();
+        int countB = typeB.getAttributeCount();
+
+        if (countA > countB) {
+            return -1;
+        }
+
+        // may still be the same featureType
+        // (Perhaps they differ on namespace?)
+        AttributeDescriptor a;
+
+        // may still be the same featureType
+        // (Perhaps they differ on namespace?)
+        int match = 0;
+
+        for (int i = 0; i < countA; i++) {
+            a = typeA.getDescriptor(i);
+
+            if (isMatch(a, typeB.getDescriptor(i))) {
+                match++;
+            } else if (isMatch(a, typeB.getDescriptor(a.getLocalName()))) {
+                // match was found in a different position
+            } else {
+                // cannot find any match for Attribute in typeA
+                return -1;
+            }
+        }
+
+        if ((countA == countB) && (match == countA)) {
+            // all attributes in typeA agreed with typeB
+            // (same order and type)
+            //            if (typeA.getNamespace() == null) {
+            //            	if(typeB.getNamespace() == null) {
+            //            		return 0;
+            //            	} else {
+            //            		return 1;
+            //            	}
+            //            } else if(typeA.getNamespace().equals(typeB.getNamespace())) {
+            //                return 0;
+            //            } else {
+            //                return 1;
+            //            }
+            return 0;
+        }
+
+        return 1;
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @param a DOCUMENT ME!
+     * @param b DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     */
+    public static boolean isMatch(AttributeDescriptor a, AttributeDescriptor b) {
+        if (a == b) {
+            return true;
+        }
+
+        if (b == null) {
+            return false;
+        }
+
+        if (a == null) {
+            return false;
+        }
+
+        if (a.equals(b)) {
+            return true;
+        }
+
+        if (a.getLocalName().equals(b.getLocalName())
+                && a.getClass().equals(b.getClass())) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Creates duplicate of feature adjusted to the provided featureType.
+     *
+     * @param featureType FeatureType requested
+     * @param feature Origional Feature from DataStore
+     *
+     * @return An instance of featureType based on feature
+     *
+     * @throws IllegalAttributeException If opperation could not be performed
+     */
+    public static SimpleFeature reType(SimpleFeatureType featureType, SimpleFeature feature)
+        throws IllegalAttributeException {
+        SimpleFeatureType origional = feature.getFeatureType();
+
+        if (featureType.equals(origional)) {
+            return SimpleFeatureBuilder.copy(feature);
+        }
+
+        String id = feature.getID();
+        int numAtts = featureType.getAttributeCount();
+        Object[] attributes = new Object[numAtts];
+        String xpath;
+
+        for (int i = 0; i < numAtts; i++) {
+            AttributeDescriptor curAttType = featureType.getDescriptor(i);
+            xpath = curAttType.getLocalName();
+            attributes[i] = duplicate(feature.getAttribute(xpath));
+        }
+
+        return SimpleFeatureBuilder.build(featureType, attributes, id);
+    }
+    
+    public static Object duplicate( Object src ) {
+//JD: this method really needs to be replaced with somethign better
+        
+        if (src == null) {
+            return null;
+        }
+
+        //
+        // The following are things I expect
+        // Features will contain.
+        // 
+        if (src instanceof String || src instanceof Integer
+                || src instanceof Double || src instanceof Float
+                || src instanceof Byte || src instanceof Boolean
+                || src instanceof Short || src instanceof Long
+                || src instanceof Character || src instanceof Number) {
+            return src;
+        }
+        
+        if (src instanceof Date) {
+            return new Date( ((Date)src).getTime() );
+        }
+        
+        if (src instanceof URL || src instanceof URI ) {
+            return src; //immutable
+        }
+
+        if (src instanceof Object[]) {
+            Object[] array = (Object[]) src;
+            Object[] copy = new Object[array.length];
+
+            for (int i = 0; i < array.length; i++) {
+                copy[i] = duplicate(array[i]);
+            }
+
+            return copy;
+        }
+
+        if (src instanceof Geometry) {
+            Geometry geometry = (Geometry) src;
+
+            return geometry.clone();
+        }
+
+        if (src instanceof SimpleFeature) {
+            SimpleFeature feature = (SimpleFeature) src;
+            return SimpleFeatureBuilder.copy(feature);
+        }
+
+        // 
+        // We are now into diminishing returns
+        // I don't expect Features to contain these often
+        // (eveything is still nice and recursive)
+        //
+        Class<? extends Object> type = src.getClass();
+
+        if (type.isArray() && type.getComponentType().isPrimitive()) {
+            int length = Array.getLength(src);
+            Object copy = Array.newInstance(type.getComponentType(), length);
+            System.arraycopy(src, 0, copy, 0, length);
+
+            return copy;
+        }
+
+        if (type.isArray()) {
+            int length = Array.getLength(src);
+            Object copy = Array.newInstance(type.getComponentType(), length);
+
+            for (int i = 0; i < length; i++) {
+                Array.set(copy, i, duplicate(Array.get(src, i)));
+            }
+
+            return copy;
+        }
+
+        if (src instanceof List) {
+            List list = (List) src;
+            List<Object> copy = new ArrayList<Object>(list.size());
+
+            for (Iterator i = list.iterator(); i.hasNext();) {
+                copy.add(duplicate(i.next()));
+            }
+
+            return Collections.unmodifiableList(copy);
+        }
+
+        if (src instanceof Map) {
+            Map map = (Map) src;
+            Map copy = new HashMap(map.size());
+
+            for (Iterator i = map.entrySet().iterator(); i.hasNext();) {
+                Map.Entry entry = (Map.Entry) i.next();
+                copy.put(entry.getKey(), duplicate(entry.getValue()));
+            }
+
+            return Collections.unmodifiableMap(copy);
+        }
+        
+        if( src instanceof GridCoverage ){
+            return src; // inmutable
+        }
+        
+
+        //
+        // I have lost hope and am returning the orgional reference
+        // Please extend this to support additional classes.
+        //
+        // And good luck getting Cloneable to work
+        throw new IllegalAttributeException("Do not know how to deep copy "
+            + type.getName());
+    }
+
+    /**
+     * Constructs an empty feature to use as a Template for new content.
+     * 
+     * <p>
+     * We may move this functionality to FeatureType.create( null )?
+     * </p>
+     *
+     * @param featureType Type of feature we wish to create
+     *
+     * @return A new Feature of type featureType
+     *
+     * @throws IllegalAttributeException if we could not create featureType
+     *         instance with acceptable default values
+     */
+    public static SimpleFeature template(SimpleFeatureType featureType)
+        throws IllegalAttributeException {
+        return SimpleFeatureBuilder.build(featureType, defaultValues(featureType), null);
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @param featureType DOCUMENT ME!
+     * @param featureID DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     *
+     * @throws IllegalAttributeException DOCUMENT ME!
+     */
+    public static SimpleFeature template(SimpleFeatureType featureType, String featureID)
+        throws IllegalAttributeException {
+        return SimpleFeatureBuilder.build(featureType, defaultValues(featureType), featureID);
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @param featureType DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     *
+     * @throws IllegalAttributeException DOCUMENT ME!
+     */
+    public static Object[] defaultValues(SimpleFeatureType featureType)
+        throws IllegalAttributeException {
+        return defaultValues(featureType, null);
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @param featureType DOCUMENT ME!
+     * @param atts DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     *
+     * @throws IllegalAttributeException DOCUMENT ME!
+     */
+    public static SimpleFeature template(SimpleFeatureType featureType, Object[] atts)
+        throws IllegalAttributeException {
+        return SimpleFeatureBuilder.build(featureType,defaultValues(featureType, atts),null);
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @param featureType DOCUMENT ME!
+     * @param featureID DOCUMENT ME!
+     * @param atts DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     *
+     * @throws IllegalAttributeException DOCUMENT ME!
+     */
+    public static SimpleFeature template(SimpleFeatureType featureType, String featureID,
+        Object[] atts) throws IllegalAttributeException {
+        return SimpleFeatureBuilder.build(featureType, defaultValues(featureType, atts), featureID);
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @param featureType DOCUMENT ME!
+     * @param values DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     *
+     * @throws IllegalAttributeException DOCUMENT ME!
+     * @throws ArrayIndexOutOfBoundsException DOCUMENT ME!
+     */
+    public static Object[] defaultValues(SimpleFeatureType featureType,
+        Object[] values) throws IllegalAttributeException {
+        if (values == null) {
+            values = new Object[featureType.getAttributeCount()];
+        } else if (values.length != featureType.getAttributeCount()) {
+            throw new ArrayIndexOutOfBoundsException("values");
+        }
+
+        for (int i = 0; i < featureType.getAttributeCount(); i++) {
+            values[i] = defaultValue(featureType.getDescriptor(i));
+        }
+
+        return values;
+    }
+
+    /**
+     * Provides a defautlValue for attributeType.
+     * 
+     * <p>
+     * Will return null if attributeType isNillable(), or attempt to use
+     * Reflection, or attributeType.parse( null )
+     * </p>
+     *
+     * @param attributeType
+     *
+     * @return null for nillable attributeType, attempt at reflection
+     *
+     * @throws IllegalAttributeException If value cannot be constructed for
+     *         attribtueType
+     */
+    public static Object defaultValue(AttributeDescriptor attributeType)
+        throws IllegalAttributeException {
+            Object value = attributeType.getDefaultValue();
+        
+        if (value == null && !attributeType.isNillable()) {
+            return null; // sometimes there is no valid default value :-(
+            // throw new IllegalAttributeException("Got null default value for non-null type.");
+        }
+        return value;
+    }
+
+    /**
+     * Returns a non-null default value for the class that is passed in.  This is a helper class an can't create a 
+     * default class for any type but it does support:
+     * <ul>
+     * <li>String</li>
+     * <li>Object - will return empty string</li>
+     * <li>Number</li>
+     * <li>Character</li>
+     * <li>JTS Geometries</li>
+     * </ul>
+     * 
+     *
+     * @param type
+     * @return
+     */
+    public static Object defaultValue(Class type){
+        if( type==String.class || type==Object.class){
+            return "";
+        }
+        if( type==Integer.class ){
+            return new Integer(0);
+        }
+        if( type==Double.class ){
+            return new Double(0);
+        }
+        if( type==Long.class ){
+            return new Long(0);
+        }
+        if( type==Short.class ){
+            return new Short((short)0);
+        }
+        if( type==Float.class ){
+            return new Float(0.0f);
+        }
+        if( type==BigDecimal.class){
+            return BigDecimal.valueOf(0);
+        }
+        if( type==BigInteger.class){
+            return BigInteger.valueOf(0);
+        }
+        if( type==Character.class ){
+            return new Character(' ');
+        }
+        if( type==Boolean.class){
+        	return Boolean.FALSE;
+        }
+        if( type==Timestamp.class)
+            return new Timestamp(System.currentTimeMillis());
+        if( type==java.sql.Date.class)
+            return new java.sql.Date(System.currentTimeMillis());
+        if( type==java.sql.Time.class)
+            return new java.sql.Time(System.currentTimeMillis());
+        if( type==java.util.Date.class)
+            return new java.util.Date();
+        
+        
+        GeometryFactory fac=new GeometryFactory();
+        Coordinate coordinate = new Coordinate(0, 0);
+        Point point = fac.createPoint(coordinate);
+
+        if( type==Point.class ){
+            return point;
+        }
+        if( type==MultiPoint.class ){
+            return fac.createMultiPoint(new Point[]{point});
+        }
+        if( type==LineString.class ){
+            return fac.createLineString(new Coordinate[]{coordinate,coordinate,coordinate,coordinate});
+        }
+        LinearRing linearRing = fac.createLinearRing(new Coordinate[]{coordinate,coordinate,coordinate,coordinate});
+        if( type==LinearRing.class ){
+            return linearRing;
+        }
+        if( type==MultiLineString.class ){
+            return fac.createMultiLineString(new LineString[]{linearRing});
+        }
+        Polygon polygon = fac.createPolygon(linearRing, new LinearRing[0]);
+        if( type==Polygon.class ){
+            return polygon;
+        }
+        if( type==MultiPolygon.class ){
+            return fac.createMultiPolygon(new Polygon[]{polygon});
+        }
+        if( type==Geometry.class ){
+        	ArrayList<Geometry> gl = new ArrayList<Geometry>();
+        	gl.add(polygon);
+        	gl.add(linearRing);
+        	gl.add(point);
+            return fac.buildGeometry(gl);
+        }
+        
+        throw new IllegalArgumentException(type+" is not supported by this method");
+    }
+    /**
+     * Creates a  FeatureReader<SimpleFeatureType, SimpleFeature> for testing.
+     *
+     * @param features Array of features
+     *
+     * @return  FeatureReader<SimpleFeatureType, SimpleFeature> spaning provided feature array
+     *
+     * @throws IOException If provided features Are null or empty
+     * @throws NoSuchElementException DOCUMENT ME!
+     */
+    public static  FeatureReader<SimpleFeatureType, SimpleFeature> reader(final SimpleFeature[] features)
+        throws IOException {
+        if ((features == null) || (features.length == 0)) {
+            throw new IOException("Provided features where empty");
+        }
+    
+        return new FeatureReader<SimpleFeatureType, SimpleFeature>() {
+                SimpleFeature[] array = features;
+                int offset = -1;
+
+                public SimpleFeatureType getFeatureType() {
+                    return features[0].getFeatureType();
+                }
+
+                public SimpleFeature next(){
+                    if (!hasNext()) {
+                        throw new NoSuchElementException("No more features");
+                    }
+
+                    return array[++offset];
+                }
+
+                public boolean hasNext(){
+                    return (array != null) && (offset < (array.length - 1));
+                }
+
+                public void close(){
+                    array = null;
+                    offset = -1;
+                }
+            };
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @param featureArray DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     *
+     * @throws IOException DOCUMENT ME!
+     * @throws RuntimeException DOCUMENT ME!
+     */
+    public static FeatureSource<SimpleFeatureType, SimpleFeature> source(final SimpleFeature[] featureArray) {
+        final SimpleFeatureType featureType;
+
+        if ((featureArray == null) || (featureArray.length == 0)) {
+            featureType = FeatureTypes.EMPTY;
+        } else {
+            featureType = featureArray[0].getFeatureType();
+        }
+
+        DataStore arrayStore = new AbstractDataStore() {
+                public String[] getTypeNames() {
+                    return new String[] { featureType.getTypeName() };
+                }
+
+                public SimpleFeatureType getSchema(String typeName)
+                    throws IOException {
+                    if ((typeName != null)
+                            && typeName.equals(featureType.getTypeName())) {
+                        return featureType;
+                    }
+
+                    throw new IOException(typeName + " not available");
+                }
+
+                protected  FeatureReader<SimpleFeatureType, SimpleFeature> getFeatureReader(String typeName)
+                    throws IOException {
+                    return reader(featureArray);
+                }
+            };
+
+        try {
+            return arrayStore.getFeatureSource(arrayStore.getTypeNames()[0]);
+        } catch (IOException e) {
+            throw new RuntimeException(
+                "Something is wrong with the geotools code, "
+                + "this exception should not happen", e);
+        }
+    }
+
+    /**
+     * Wrap up the provided FeatureCollection as a feature soruce; allowing queries to be performed etc...
+     *
+     * @param collection FeatureCollection
+     *
+     * @return FeatureSource
+     *
+     * @throws NullPointerException If the collection is null
+     * @throws RuntimeException 
+     */
+    public static FeatureSource<SimpleFeatureType, SimpleFeature> source(final FeatureCollection<SimpleFeatureType, SimpleFeature> collection) {
+        if (collection == null) {
+            throw new NullPointerException();
+        }
+
+        DataStore store = new CollectionDataStore(collection);
+
+        try {
+            return store.getFeatureSource(store.getTypeNames()[0]);
+        } catch (IOException e) {
+            throw new RuntimeException(
+                "FeatureCollection is not consistent, unable to access contents", e);
+        }
+    }
+    
+    public static FeatureCollection<SimpleFeatureType, SimpleFeature> results(SimpleFeature[] featureArray){
+        return results(collection(featureArray));
+    }
+
+    /**
+     * Returns collection if non empty.
+     *
+     * @param collection
+     *
+     * @return provided collection
+     *
+     * @throws IOException Raised if collection was empty
+     */
+    public static FeatureCollection<SimpleFeatureType, SimpleFeature> results(final FeatureCollection<SimpleFeatureType, SimpleFeature> collection){
+        if (collection.size() == 0) {
+            //throw new IOException("Provided collection was empty");
+        }
+        return collection;
+    }
+
+    /**
+     * Adapt a collection to a reader for use with FeatureStore.setFeatures( reader ).
+     *
+     * @param collection Collection of SimpleFeature
+     *
+     * @return FeatureRedaer over the provided contents
+     * @throws IOException IOException if there is any problem reading the content.
+     */
+    public static  FeatureReader<SimpleFeatureType, SimpleFeature> reader(Collection<SimpleFeature> collection)
+        throws IOException {
+        return reader(collection.toArray(
+                new SimpleFeature[collection.size()]));
+    }
+    /**
+     * Adapt a collection to a reader for use with FeatureStore.setFeatures( reader ).
+     *
+     * @param collection Collection of SimpleFeature
+     *
+     * @return FeatureRedaer over the provided contents
+     * @throws IOException IOException if there is any problem reading the content.
+     */   
+    public static FeatureReader<SimpleFeatureType, SimpleFeature> reader(
+            FeatureCollection<SimpleFeatureType,SimpleFeature> collection) throws IOException {
+        return reader(collection
+                .toArray(new SimpleFeature[collection.size()]));
+    }
+
+    /**
+     * Copies the provided features into a FeatureCollection.
+     * <p>
+     * Often used when gathering features for FeatureStore:<pre><code>
+     * featureStore.addFeatures( DataUtilities.collection(array));
+     * </code></pre>
+     * 
+     * @param features Array of features
+     * @return FeatureCollection
+     */
+    public static FeatureCollection<SimpleFeatureType, SimpleFeature> collection(SimpleFeature[] features) {
+        FeatureCollection<SimpleFeatureType, SimpleFeature> collection = FeatureCollections.newCollection();
+		final int length = features.length;
+		for (int i = 0; i < length; i++) {
+            collection.add(features[i]);
+        }
+        return collection;
+    }
+    /**
+     * Copies the provided features into a FeatureCollection.
+     * <p>
+     * Often used when gathering a FeatureCollection<SimpleFeatureType, SimpleFeature> into memory.
+     * 
+     * @param FeatureCollection<SimpleFeatureType, SimpleFeature> the features to add to a new feature collection.
+     * @return FeatureCollection
+     */
+    public static DefaultFeatureCollection collection( FeatureCollection<SimpleFeatureType, SimpleFeature> featureCollection ){
+        return new DefaultFeatureCollection( featureCollection );
+    }
+    /**
+     * Copies the provided fetaures into a List.
+     * 
+     * @param featureCollection
+     * @return List of features copied into memory
+     */
+    public static List<SimpleFeature> list( FeatureCollection<SimpleFeatureType, SimpleFeature> featureCollection ){
+        final ArrayList<SimpleFeature> list = new ArrayList<SimpleFeature>();
+        try {
+            featureCollection.accepts( new FeatureVisitor(){
+                public void visit(Feature feature) {
+                    list.add( (SimpleFeature) feature );
+                }            
+            }, null );
+        }
+        catch( IOException ignore ){
+        }
+        return list;
+    }
+    /**
+     * Copies the feature ids from each and every feature into a set.
+     * <p>
+     * This method can be slurp an in memory record of the contents of a
+     * @param featureCollection
+     * @return
+     */
+    public static Set<String> fidSet( FeatureCollection<?,?> featureCollection ){
+        final HashSet<String> fids = new HashSet<String>();
+        try {
+            featureCollection.accepts( new FeatureVisitor(){
+                public void visit(Feature feature) {
+                    fids.add( feature.getIdentifier().getID() );
+                }            
+            }, null );
+        }
+        catch( IOException ignore ){
+        }
+        return fids;
+    }
+    /**
+     * Copies the provided features into a FeatureCollection.
+     * <p>
+     * Often used when gathering a FeatureCollection<SimpleFeatureType, SimpleFeature> into memory.
+     *
+     * @param list features to add to a new FeatureCollection
+     * @return FeatureCollection
+     */
+    public static FeatureCollection<SimpleFeatureType, SimpleFeature> collection( List<SimpleFeature> list ) {
+        FeatureCollection<SimpleFeatureType, SimpleFeature> collection = FeatureCollections.newCollection();
+        for ( SimpleFeature feature : list ){
+            collection.add( feature );
+        }
+        return collection;
+    }
+
+    
+    /**
+     * Copies the provided features into a FeatureCollection.
+     * <p>
+     * Often used when gathering features for FeatureStore:<pre><code>
+     * featureStore.addFeatures( DataUtilities.collection(feature));
+     * </code></pre>
+     * 
+     * @param feature a feature to add to a new collection
+     * @return FeatureCollection
+     */
+    public static FeatureCollection<SimpleFeatureType, SimpleFeature> collection( SimpleFeature feature ){
+        FeatureCollection<SimpleFeatureType, SimpleFeature> collection = FeatureCollections.newCollection();
+        collection.add(feature);
+        return collection;
+    }
+
+    /**
+     * Copies the provided reader into a FeatureCollection, reader will be closed.
+     * <p>
+     * Often used when gathering features for FeatureStore:<pre><code>
+     * featureStore.addFeatures( DataUtilities.collection(reader));
+     * </code></pre>
+     * 
+     * @return FeatureCollection
+     */
+    public static FeatureCollection<SimpleFeatureType, SimpleFeature> collection(FeatureReader <SimpleFeatureType, SimpleFeature> reader) throws IOException {
+        FeatureCollection<SimpleFeatureType, SimpleFeature> collection = FeatureCollections.newCollection();        
+        try {
+            while( reader.hasNext() ) {
+                try {
+                    collection.add( reader.next() );
+                } catch (NoSuchElementException e) {
+                    throw (IOException) new IOException("EOF").initCause( e );
+                } catch (IllegalAttributeException e) {
+                    throw (IOException) new IOException().initCause( e );
+                }                
+            }
+        }
+        finally {
+            reader.close();
+        }
+        return collection;
+    }
+    /**
+     * Copies the provided reader into a FeatureCollection, reader will be closed.
+     * <p>
+     * Often used when gathering features for FeatureStore:<pre><code>
+     * featureStore.addFeatures( DataUtilities.collection(reader));
+     * </code></pre>
+     * 
+     * @return FeatureCollection
+     */
+    public static FeatureCollection<SimpleFeatureType, SimpleFeature> collection(FeatureIterator<SimpleFeature> reader) throws IOException {
+        FeatureCollection<SimpleFeatureType, SimpleFeature> collection = FeatureCollections.newCollection();        
+        try {
+            while( reader.hasNext() ) {
+                try {
+                    collection.add( reader.next() );
+                } catch (NoSuchElementException e) {
+                    throw (IOException) new IOException("EOF").initCause( e );
+                }               
+            }
+        }
+        finally {
+            reader.close();
+        }
+        return collection;
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @param att DOCUMENT ME!
+     * @param otherAtt DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     */
+    public static boolean attributesEqual(Object att, Object otherAtt) {
+        if (att == null) {
+            if (otherAtt != null) {
+                return false;
+            }
+        } else {
+            if (!att.equals(otherAtt)) {
+                if (att instanceof Geometry && otherAtt instanceof Geometry) {
+                    // we need to special case Geometry
+                    // as JTS is broken
+                    // Geometry.equals( Object ) and Geometry.equals( Geometry )
+                    // are different 
+                    // (We should fold this knowledge into AttributeType...)
+                    // 
+                    if (!((Geometry) att).equals((Geometry) otherAtt)) {
+                        return false;
+                    }
+                } else {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Create a derived FeatureType
+     * 
+     * <p></p>
+     *
+     * @param featureType
+     * @param properties - if null, every property of the feature type in input will be used
+     * @param override
+     *
+     *
+     * @throws SchemaException
+     */
+    public static SimpleFeatureType createSubType(SimpleFeatureType featureType,
+            String[] properties, CoordinateReferenceSystem override)
+            throws SchemaException {
+        URI namespaceURI = null;
+        if ( featureType.getName().getNamespaceURI() != null ) {
+            try {
+                namespaceURI = new URI( featureType.getName().getNamespaceURI() );
+            } catch (URISyntaxException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        
+        return createSubType( featureType, properties, override, featureType.getTypeName(), namespaceURI );
+
+    }
+
+    public static SimpleFeatureType createSubType(SimpleFeatureType featureType,
+        String[] properties, CoordinateReferenceSystem override, String typeName, URI namespace )
+        throws SchemaException {
+        
+        if ((properties == null) && (override == null)) {
+            return featureType;
+        }
+        
+        if(properties == null) {
+          properties = new String[featureType.getAttributeCount()];
+          for (int i = 0; i < properties.length; i++) {
+            properties[i] = featureType.getDescriptor(i).getLocalName();
+          }
+        }
+
+        String namespaceURI = namespace != null ? namespace.toString() : null;
+        boolean same = featureType.getAttributeCount() == properties.length &&
+            featureType.getTypeName().equals( typeName ) &&
+            Utilities.equals(featureType.getName().getNamespaceURI(), namespaceURI );
+            
+
+        for (int i = 0; (i < featureType.getAttributeCount()) && same; i++) {
+            AttributeDescriptor type = featureType.getDescriptor(i);
+            same = type.getLocalName().equals(properties[i])
+                && (((override != null)
+                && type instanceof GeometryDescriptor)
+                ? assertEquals(override, ((GeometryDescriptor) type).getCoordinateReferenceSystem())
+                : true);
+        }
+
+        if (same) {
+            return featureType;
+        }
+
+        AttributeDescriptor[] types = new AttributeDescriptor[properties.length];
+
+        for (int i = 0; i < properties.length; i++) {
+            types[i] = featureType.getDescriptor(properties[i]);
+
+            if ((override != null) && types[i] instanceof GeometryDescriptor) {
+                AttributeTypeBuilder ab = new AttributeTypeBuilder();
+                ab.init( types[i] );
+                ab.setCRS(override);
+                types[i] = ab.buildDescriptor(types[i].getLocalName(), ab.buildGeometryType());
+            }
+        }
+
+        if( typeName == null ) typeName = featureType.getTypeName();
+        if( namespace == null && featureType.getName().getNamespaceURI() != null )
+            try {
+                namespace = new URI(featureType.getName().getNamespaceURI());
+            } catch (URISyntaxException e) {
+                throw new RuntimeException(e);
+            }    
+            
+            
+        
+        SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
+        tb.setName( typeName );
+        tb.setNamespaceURI( namespace );
+        tb.addAll(types);
+        
+        return tb.buildFeatureType();
+    }
+    
+    private static boolean assertEquals(Object o1, Object o2){
+    	return o1 == null && o2 == null? true :
+    		(o1 != null? o1.equals(o2) : false);
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @param featureType DOCUMENT ME!
+     * @param properties DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     *
+     * @throws SchemaException DOCUMENT ME!
+     */
+    public static SimpleFeatureType createSubType(SimpleFeatureType featureType,
+        String[] properties) throws SchemaException {
+        if (properties == null) {
+            return featureType;
+        }
+
+        boolean same = featureType.getAttributeCount() == properties.length;
+
+        for (int i = 0; (i < featureType.getAttributeCount()) && same; i++) {
+            same = featureType.getDescriptor(i).getLocalName().equals(properties[i]);
+        }
+
+        if (same) {
+            return featureType;
+        }
+
+        SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
+        tb.setName( featureType.getName() );
+        
+        for (int i = 0; i < properties.length; i++) {
+            tb.add( featureType.getDescriptor(properties[i]) );
+        }
+        return tb.buildFeatureType();
+    }
+
+    /**
+     * Utility method for FeatureType construction.
+     * <p>
+     * Will parse a String of the form: <i>"name:Type,name2:Type2,..."</i>
+     * </p>
+     * 
+     * <p>
+     * Where <i>Type</i> is defined by createAttribute.
+     * </p>
+     * 
+     * <p>
+     * You may indicate the default Geometry with an astrix: "*geom:Geometry". You
+     * may also indicate the srid (used to look up a EPSG code).
+     * </p>
+     * 
+     * <p>
+     * Examples:
+     * <ul>
+     * <li><code>name:"",age:0,geom:Geometry,centroid:Point,url:java.io.URL"</code>
+     * <li><code>id:String,polygonProperty:Polygon:srid=32615</code>
+     * </ul>
+     * </p>
+     *
+     * @param identification identification of FeatureType:
+     *        (<i>namesapce</i>).<i>typeName</i>
+     * @param typeSpec Specification for FeatureType
+     *
+     *
+     * @throws SchemaException
+     */
+    public static SimpleFeatureType createType(String identification, String typeSpec)
+        throws SchemaException {
+        int split = identification.lastIndexOf('.');
+        String namespace = (split == -1) ? null
+                                         : identification.substring(0, split);
+        String typeName = (split == -1) ? identification
+                                        : identification.substring(split + 1);
+        
+        return createType(namespace, typeName, typeSpec);
+    }
+    
+    /**
+     * Utility method for FeatureType construction.
+     * <p>
+     * Will parse a String of the form: <i>"name:Type,name2:Type2,..."</i>
+     * </p>
+     * 
+     * <p>
+     * Where <i>Type</i> is defined by createAttribute.
+     * </p>
+     * 
+     * <p>
+     * You may indicate the default Geometry with an astrix: "*geom:Geometry". You
+     * may also indicate the srid (used to look up a EPSG code).
+     * </p>
+     * 
+     * <p>
+     * Examples:
+     * <ul>
+     * <li><code>name:"",age:0,geom:Geometry,centroid:Point,url:java.io.URL"</code>
+     * <li><code>id:String,polygonProperty:Polygon:srid=32615</code>
+     * </ul>
+     * </p>
+     *
+     * @param identification identification of FeatureType:
+     *        (<i>namesapce</i>).<i>typeName</i>
+     * @param typeSpec Specification for FeatureType
+     *
+     *
+     * @throws SchemaException
+     */
+    public static SimpleFeatureType createType(String namespace, String typeName, String typeSpec)
+        throws SchemaException {
+        SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
+        tb.setName( typeName );
+        tb.setNamespaceURI(namespace);
+        
+        String[] types = typeSpec.split(",");
+         
+        AttributeDescriptor attributeType;
+        
+        for (int i = 0; i < types.length; i++) {
+            boolean defaultGeometry = types[i].startsWith("*");
+            if (types[i].startsWith("*")) {
+                types[i] = types[i].substring(1);
+            }
+
+            attributeType = createAttribute(types[i]);
+            tb.add(attributeType);
+            
+            if ( defaultGeometry ) {
+                tb.setDefaultGeometry(attributeType.getLocalName());
+            }
+        }
+
+        return tb.buildFeatureType();
+    }
+
+    
+    
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @param type DOCUMENT ME!
+     * @param fid DOCUMENT ME!
+     * @param text DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     *
+     * @throws IllegalAttributeException DOCUMENT ME!
+     */
+    public static SimpleFeature parse(SimpleFeatureType type, String fid, String[] text)
+        throws IllegalAttributeException {
+        Object[] attributes = new Object[text.length];
+
+        for (int i = 0; i < text.length; i++) {
+            AttributeType attType = type.getDescriptor(i).getType();
+            attributes[i] = Converters.convert(text[i], attType.getBinding());
+        }
+
+        return SimpleFeatureBuilder.build(type, attributes, fid);
+    }
+
+    /**
+     * A "quick" String representation of a FeatureType.
+     * <p>
+     * This string representation may be used with createType( name, spec ).
+     * </p>
+     * @param featureType FeatureType to represent
+     *
+     * @return The string "specification" for the featureType
+     */
+    public static String spec(FeatureType featureType) {
+        Collection<PropertyDescriptor> types = featureType.getDescriptors();
+        StringBuffer buf = new StringBuffer();
+        
+        for( PropertyDescriptor type : types ){
+            buf.append(type.getName().getLocalPart());
+            buf.append(":");
+            buf.append(typeMap(type.getType().getBinding()));
+            if(type instanceof GeometryDescriptor) {
+                GeometryDescriptor gd = (GeometryDescriptor) type;
+                if(gd.getCoordinateReferenceSystem() != null && gd.getCoordinateReferenceSystem().getIdentifiers() != null) {                    
+                    for (Iterator<ReferenceIdentifier> it = gd.getCoordinateReferenceSystem().getIdentifiers().iterator(); it.hasNext();) {
+                        ReferenceIdentifier id = it.next();
+
+                        if ((id.getAuthority() != null)
+                                && id.getAuthority().getTitle().equals(Citations.EPSG.getTitle())) {
+                            buf.append(":srid=" + id.getCode());
+                            break;
+                        }
+                        
+                    }
+                }
+            }
+            buf.append(",");            
+        }
+        buf.delete(buf.length()-1,buf.length()); // remove last ","
+
+        return buf.toString();
+    }
+
+    static Class type(String typeName) throws ClassNotFoundException {
+        if (typeMap.containsKey(typeName)) {
+            return typeMap.get(typeName);
+        }
+
+        return Class.forName(typeName);
+    }
+
+    static String typeMap(Class type) {
+        if( typeEncode.containsKey(type)){
+            return typeEncode.get( type );
+        }        
+        /*
+        SortedSet<String> choose = new TreeSet<String>();
+        for (Iterator i = typeMap.entrySet().iterator(); i.hasNext();) {
+            Map.Entry entry = (Entry) i.next();
+
+            if (entry.getValue().equals(type)) {
+                choose.add( (String) entry.getKey() );
+            }
+        }
+        if( !choose.isEmpty() ){
+            return choose.last();
+        }
+        */
+        return type.getName();
+    }
+
+    /**
+     * Takes two {@link Query}objects and produce a new one by mixing the
+     * restrictions of both of them.
+     * 
+     * <p>
+     * The policy to mix the queries components is the following:
+     * 
+     * <ul>
+     * <li>
+     * typeName: type names MUST match (not checked if some or both queries
+     * equals to <code>Query.ALL</code>)
+     * </li>
+     * <li>
+     * handle: you must provide one since no sensible choice can be done
+     * between the handles of both queries
+     * </li>
+     * <li>
+     * maxFeatures: the lower of the two maxFeatures values will be used (most
+     * restrictive)
+     * </li>
+     * <li>
+     * attributeNames: the attributes of both queries will be joined in a
+     * single set of attributes. IMPORTANT: only <b><i>explicitly</i></b>
+     * requested attributes will be joint, so, if the method
+     * <code>retrieveAllProperties()</code> of some of the queries returns
+     * <code>true</code> it does not means that all the properties will be
+     * joined. You must create the query with the names of the properties you
+     * want to load.
+     * </li>
+     * <li>
+     * filter: the filtets of both queries are or'ed
+     * </li>
+     * <li>
+     * <b>any other query property is ignored</b> and no guarantees are made of
+     * their return values, so client code shall explicitly care of hints, startIndex, etc.,
+     * if needed.
+     * </li>
+     * </ul>
+     * </p>
+     *
+     * @param firstQuery Query against this DataStore
+     * @param secondQuery DOCUMENT ME!
+     * @param handle DOCUMENT ME!
+     *
+     * @return Query restricted to the limits of definitionQuery
+     *
+     * @throws NullPointerException if some of the queries is null
+     * @throws IllegalArgumentException if the type names of both queries do
+     *         not match
+     */
+    public static Query mixQueries(Query firstQuery, Query secondQuery,
+        String handle) {
+        if ((firstQuery == null) || (secondQuery == null)) {
+            throw new NullPointerException("got a null query argument");
+        }
+
+        if (firstQuery.equals(Query.ALL)) {
+            return secondQuery;
+        } else if (secondQuery.equals(Query.ALL)) {
+            return firstQuery;
+        }
+
+        if ((firstQuery.getTypeName() != null)
+                && (secondQuery.getTypeName() != null)) {
+            if (!firstQuery.getTypeName().equals(secondQuery.getTypeName())) {
+                String msg = "Type names do not match: "
+                    + firstQuery.getTypeName() + " != "
+                    + secondQuery.getTypeName();
+                throw new IllegalArgumentException(msg);
+            }
+        }
+        
+        // mix versions, if possible
+        String version;
+        if(firstQuery.getVersion() != null) {
+            if(secondQuery.getVersion() != null && !secondQuery.getVersion().equals(firstQuery.getVersion()))
+                throw new IllegalArgumentException("First and second query refer different versions");
+            version = firstQuery.getVersion();
+        } else {
+            version = secondQuery.getVersion();
+        }
+            
+
+        //none of the queries equals Query.ALL, mix them
+        //use the more restrictive max features field
+        int maxFeatures = Math.min(firstQuery.getMaxFeatures(),
+                secondQuery.getMaxFeatures());
+
+        //join attributes names
+        String[] propNames = joinAttributes(firstQuery.getPropertyNames(),
+                secondQuery.getPropertyNames());
+
+        //join filters
+        Filter filter = firstQuery.getFilter();
+        Filter filter2 = secondQuery.getFilter();
+
+        if ((filter == null) || filter.equals(Filter.INCLUDE)) {
+            filter = filter2;
+        } else if ((filter2 != null) && !filter2.equals(Filter.INCLUDE)) {
+            filter = ff.and( filter, filter2);
+        }
+        Integer start=0;
+        if( firstQuery.getStartIndex() != null ){
+        	start = firstQuery.getStartIndex();
+        }
+        if( secondQuery.getStartIndex() != null ){
+        	start += secondQuery.getStartIndex();
+        }
+        //build the mixed query
+        String typeName = firstQuery.getTypeName() != null? 
+        		firstQuery.getTypeName() : secondQuery.getTypeName();
+
+        DefaultQuery mixed = new DefaultQuery(typeName, filter, maxFeatures, propNames, handle);
+        mixed.setVersion(version);
+     	if(start != 0){
+		    mixed.setStartIndex(start);
+		}
+        return mixed;
+    }
+
+    /**
+     * Creates a set of attribute names from the two input lists of names,
+     * maintaining the order of the first list and appending the non repeated
+     * names of the second.
+     * <p>
+     * In the case where both lists are <code>null</code>, <code>null</code> 
+     * is returned.
+     * </p>
+     *
+     * @param atts1 the first list of attribute names, who's order will be
+     *        maintained
+     * @param atts2 the second list of attribute names, from wich the non
+     *        repeated names will be appended to the resulting list
+     *
+     * @return Set of attribute names from <code>atts1</code> and
+     *         <code>atts2</code>
+     */
+    private static String[] joinAttributes(String[] atts1, String[] atts2) {
+        String[] propNames = null;
+
+        if ( atts1 == null && atts2 == null ) {
+        	return null;
+        }
+        
+        List<String> atts = new LinkedList<String>();
+
+        if (atts1 != null) {
+            atts.addAll(Arrays.asList(atts1));
+        }
+
+        if (atts2 != null) {
+            for (int i = 0; i < atts2.length; i++) {
+                if (!atts.contains(atts2[i])) {
+                    atts.add(atts2[i]);
+                }
+            }
+        }
+
+        propNames = new String[atts.size()];
+        atts.toArray(propNames);
+
+        return propNames;
+    }
+
+    /**
+     * Returns AttributeType based on String specification (based on UML).
+     * 
+     * <p>
+     * Will parse a String of the form: <i>"name:Type:hint"</i>
+     * </p>
+     * 
+     * <p>
+     * Where <i>Type</i> is:
+     * </p>
+     * 
+     * <ul>
+     * <li>
+     * 0,Interger,int: represents Interger
+     * </li>
+     * <li>
+     * 0.0, Double, double: represents Double
+     * </li>
+     * <li>
+     * "",String,string: represents String
+     * </li>
+     * <li>
+     * Geometry: represents Geometry
+     * </li>
+     * <li>
+     * <i>full.class.path</i>: represents java type
+     * </li>
+     * </ul>
+     * 
+     * <p>
+     * Where <i>hint</i> is "hint1;hint2;...;hintN", in which "hintN" is one 
+     * of:
+     * <ul>
+     *  <li><code>nillable</code></li>
+     *  <li><code>srid=<#></code></li>
+     * </ul>
+     * </p>
+     *
+     * @param typeSpec
+     *
+     *
+     * @throws SchemaException If typeSpect could not be interpreted
+     */
+    static AttributeDescriptor createAttribute(String typeSpec)
+        throws SchemaException {
+        int split = typeSpec.indexOf(":");
+
+        String name;
+        String type;
+        String hint = null;
+
+        if (split == -1) {
+            name = typeSpec;
+            type = "String";
+        } else {
+            name = typeSpec.substring(0, split);
+
+            int split2 = typeSpec.indexOf(":", split + 1);
+
+            if (split2 == -1) {
+                type = typeSpec.substring(split + 1);
+            } else {
+                type = typeSpec.substring(split + 1, split2);
+                hint = typeSpec.substring(split2 + 1);
+            }
+        }
+
+        try {
+            boolean nillable = true;
+            CoordinateReferenceSystem crs = null;
+            
+            if ( hint != null ) {
+                StringTokenizer st = new StringTokenizer( hint, ";" );
+                while ( st.hasMoreTokens() ) {
+                    String h = st.nextToken();
+                    h = h.trim();
+                    
+                    //nillable?
+                    //JD: i am pretty sure this hint is useless since the 
+                    // default is to make attributes nillable
+                    if ( h.equals( "nillable" )) {
+                        nillable = true;
+                    }
+                    //spatial reference identieger?
+                    if ( h.startsWith("srid=" )) {
+                        String srid = h.split("=")[1];
+                        Integer.parseInt( srid );
+                        try {
+                            crs = CRS.decode( "EPSG:" + srid );
+                        } 
+                        catch( Exception e ) {
+                            String msg = "Error decoding srs: " + srid;
+                            throw new SchemaException( msg, e );
+                        }
+                    }
+                }
+            }
+            
+            Class clazz = type(type);
+            if(Geometry.class.isAssignableFrom(clazz)) {
+            	GeometryType at = new GeometryTypeImpl(new NameImpl( name ), clazz , crs, false, false, Collections.EMPTY_LIST, null, null );
+	            return new GeometryDescriptorImpl( at, new NameImpl(name), 0,1, nillable, null );
+            } else {
+	            AttributeType at = new AttributeTypeImpl( new NameImpl( name ), clazz , false, false, Collections.EMPTY_LIST, null, null );
+	            return new AttributeDescriptorImpl( at, new NameImpl(name), 0,1, nillable, null );
+            }
+        } catch (ClassNotFoundException e) {
+            throw new SchemaException("Could not type " + name + " as:" + type, e);
+        }
+    }
+
+    /**
+     * Manually calculates the bounds of a feature collection.
+     * 
+     * @param collection
+     * @return
+     */
+    public static Envelope bounds(
+            FeatureCollection<? extends FeatureType, ? extends Feature> collection) {
+        FeatureIterator<? extends Feature> i = collection.features();
+        try {
+            ReferencedEnvelope bounds = new ReferencedEnvelope(collection.getSchema()
+                    .getCoordinateReferenceSystem());
+            if (!i.hasNext()) {
+                bounds.setToNull();
+                return bounds;
+            }
+
+            bounds.init(((SimpleFeature) i.next()).getBounds());
+            return bounds;
+        } finally {
+            i.close();
+        }
+    }
+    
+
+	/**
+	 * Changes the ending (e.g. ".sld") of a {@link URL}
+	 * 
+	 * @param url
+	 *            {@link URL} like <code>file:/sds/a.bmp</code> or
+	 *            <code>http://www.some.org/foo/bar.shp</code>
+	 * @param postfix
+	 *            New file extension for the {@link URL} without <code>.</code>
+	 * 
+	 * @return A new {@link URL} with new extension.
+	 * 
+	 * @throws {@link MalformedURLException} if the new {@link URL} can not be
+	 *         created.
+	 */
+	public static URL changeUrlExt(final URL url, final String postfix)
+			throws IllegalArgumentException {
+		String a = url.toExternalForm();
+		final int lastDotPos = a.lastIndexOf('.');
+		if (lastDotPos >= 0)
+			a = a.substring(0, lastDotPos);
+		a = a + "." + postfix;
+		try {
+			return new URL(a);
+		} catch (final MalformedURLException e) {
+			throw new IllegalArgumentException("can't create a new URL for "+ url + " with new extension " + postfix, e);
+		}
+	}
+
+	/**
+	 * The function is supposed to be equivalent to {@link File}.getParent().
+	 * The {@link URL} is converted to a String, truncated to the last / and
+	 * then recreated as a new URL.
+	 * 
+	 * @throws {@link MalformedURLException} if the parent {@link URL} can not
+	 *         be created.
+	 */
+	public static URL getParentUrl(final URL url) throws MalformedURLException {
+		String a = url.toExternalForm();
+		final int lastDotPos = a.lastIndexOf('/');
+		if (lastDotPos >= 0)
+			a = a.substring(0, lastDotPos);
+		
+		/**
+		 * The parent of jar:file:some!/bar.file is jar:file:some!/, not jar:file:some!  
+		 */
+		if (a.endsWith("!")) a+="/";
+		
+		return new URL(a);
+	}
+
+	/**
+	 * Extends an {@link URL}.
+	 * 
+	 * @param base
+	 *            Has to be a {@link URL} pointing to a directory. If it doesn't
+	 *            end with a <code>/</code> it will be added automatically.
+	 * @param extension
+	 *            The part that will be added to the {@link URL}
+	 * 
+	 * @throws MalformedURLException
+	 *             if the new {@link URL} can not be created.
+	 */
+	public static URL extendURL(URL base, String extension)
+			throws MalformedURLException {
+		if(base==null)
+			throw new NullPointerException(Errors.format(ErrorKeys.NULL_ARGUMENT_$1,"base"));
+		if(extension==null)
+			throw new NullPointerException(Errors.format(ErrorKeys.NULL_ARGUMENT_$1,"extension"));
+		String a = base.toExternalForm();
+		if (!a.endsWith("/"))
+			a += "/";
+		a += extension;
+		return new URL(a);
+	}
+	
+    /**
+     * Checks that a {@link File} is a real file, exists and is readable.
+     * 
+     * @param file the {@link File} instance to check. Must not be null.
+     * @param logger an optional {@link Logger} (can be null) where to log detailed
+     *          info about the file properties (path/readable/hidden/writable)  
+     * 
+     * @return {@code true} in case the file is a real file, exists and is readable; 
+     *          {@code false} otherwise.
+     */
+    public static boolean checkFileReadable(final File file, final Logger logger) {
+        if (logger != null && logger.isLoggable(Level.FINE)) {
+            final StringBuilder builder = new StringBuilder("Checking file:")
+            .append(file.getAbsolutePath()).append("\n")
+            .append("canRead:").append(file.canRead()).append("\n")
+            .append("isHidden:").append(file.isHidden()).append("\n")
+            .append("isFile").append(file.isFile()).append("\n")
+            .append("canWrite").append(file.canWrite()).append("\n");
+            logger.fine(builder.toString());
+        }
+        if (!file.exists() || !file.canRead() || !file.isFile())
+            return false;
+        return true;
+    }
+    
+    /**
+     * Checks that the provided directory path refers to an existing/readable directory.
+     * Finally, return it as a normalized directory path (removing double and single dot path steps 
+     * if any) followed by the separator char if missing ({@code '/'} On UNIX systems; {@code '\\}
+     * on Microsoft Windows systems. 
+     * 
+     * @param directoryPath the input directory path. Must not be null.
+     * @return the re-formatted directory path. 
+     * @throws IllegalArgumentException in case the specified path doesn't rely on a 
+     *          existing/readable directory.
+     */
+    public static File checkDirectory(File file)
+            throws IllegalArgumentException {
+        String directoryPath = file.getPath();
+        File inDir = file;
+        if(!inDir.isDirectory()){
+            throw new IllegalArgumentException("Not a directory: "+directoryPath );
+        }
+        if (!inDir.canRead()) {
+            throw new IllegalArgumentException("Not a writable directory: "+ directoryPath );
+        }
+        try {
+            directoryPath = inDir.getCanonicalPath();
+        } catch (IOException e) {
+            throw new IllegalArgumentException(e);
+        }
+        /*
+        directoryPath = FilenameUtils.normalize(directoryPath);
+        if (!directoryPath.endsWith(File.separator)){
+            directoryPath = directoryPath + File.separator;
+        }
+        */
+        // test to see if things are still good
+        inDir = new File(directoryPath);
+        if(!inDir.isDirectory()){
+            throw new IllegalArgumentException("Not a directory: "+directoryPath );
+        }
+        if (!inDir.canRead()) {
+            throw new IllegalArgumentException("Not a writable directory: "+ directoryPath );
+        }
+        return new File(directoryPath);
+    }
+    
+    /**
+     * Returns a {@link IOFileFilter} obtained by excluding from the first input filter argument, 
+     * the additional filter arguments. 
+     * 
+     * @param inputFilter the initial filter from which to exclude other ones. 
+     * @param filters additional filters to be excluded 
+     * 
+     * @return the updated {@link IOFileFilter} 
+     */
+    public static FilenameFilter excludeFilters(final FilenameFilter inputFilter,
+            final FilenameFilter... filters) {
+        return new FilenameFilter() {
+            public boolean accept(File dir, String name) {
+                if( inputFilter.accept(dir, name)){
+                    for( FilenameFilter exclude : filters ){
+                        if( exclude.accept(dir, name)){
+                            return false;
+                        }
+                    }
+                    return true;
+                }               
+                return false;
+            }
+        };
+    }
+    
+    /**
+     * Returns a {@link IOFileFilter} obtained by adding to the first input filter argument, 
+     * the additional filter arguments. 
+     * 
+     * @param inputFilter the initial filter to which to add other ones. 
+     * @param filters additional filters to be included in the main filter. 
+     * 
+     * @return the updated {@link IOFileFilter} 
+     */
+    public static FilenameFilter includeFilters(final FilenameFilter inputFilter,
+            final FilenameFilter... filters) {
+        return new FilenameFilter() {
+            public boolean accept(File dir, String name) {
+                if( inputFilter.accept(dir, name)){
+                    return true;
+                }
+                for( FilenameFilter include : filters ){
+                    if( include.accept(dir, name)){
+                        return true;
+                    }
+                }
+                return false;
+            }
+        };
+    }
+
+}


Property changes on: trunk/src_junit/org/geotools/data/DataUtilities.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Id URL
Name: svn:eol-style
   + native



More information about the Schmitzm-commits mailing list