[Schmitzm-commits] r420 - in branches/1.0-gt2-2.6/src: gtmig/org/geotools/swing schmitzm/geotools/feature schmitzm/geotools/gui schmitzm/io skrueger skrueger/geotools skrueger/i8n skrueger/swing

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Thu Oct 1 22:23:11 CEST 2009


Author: alfonx
Date: 2009-10-01 22:22:48 +0200 (Thu, 01 Oct 2009)
New Revision: 420

Added:
   branches/1.0-gt2-2.6/src/skrueger/geotools/AttributeMetadataMap.java
   branches/1.0-gt2-2.6/src/skrueger/geotools/Copyable.java
   branches/1.0-gt2-2.6/src/skrueger/swing/Cancellable.java
   branches/1.0-gt2-2.6/src/skrueger/swing/CancellableDialog.java
   branches/1.0-gt2-2.6/src/skrueger/swing/CancellableDialogAdapter.java
   branches/1.0-gt2-2.6/src/skrueger/swing/Checkable.java
   branches/1.0-gt2-2.6/src/skrueger/swing/DialogManager.java
   branches/1.0-gt2-2.6/src/skrueger/swing/TranslationsAskJPanel.java
Modified:
   branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/JMapPane.java
   branches/1.0-gt2-2.6/src/schmitzm/geotools/feature/FeatureUtil.java
   branches/1.0-gt2-2.6/src/schmitzm/geotools/gui/GridPanelFormatter.java
   branches/1.0-gt2-2.6/src/schmitzm/geotools/gui/JMapPane.java
   branches/1.0-gt2-2.6/src/schmitzm/io/IOUtil.java
   branches/1.0-gt2-2.6/src/skrueger/AttributeMetaData.java
   branches/1.0-gt2-2.6/src/skrueger/geotools/StyledFS.java
   branches/1.0-gt2-2.6/src/skrueger/geotools/StyledFeatureCollection.java
   branches/1.0-gt2-2.6/src/skrueger/geotools/StyledFeaturesInterface.java
   branches/1.0-gt2-2.6/src/skrueger/geotools/StyledLayerUtil.java
   branches/1.0-gt2-2.6/src/skrueger/i8n/Translation.java
   branches/1.0-gt2-2.6/src/skrueger/swing/TranslationAskJDialog.java
Log:
* Lots of changes in this big commit for GP 1.3 
* New Interfaces: Checkable, Copyable, Cancellable, CancellableDialogAdapter to improve the GUI
* New DialogManager to unify the handling of all dialogs.
* GP-Feature: The dialog for editing/translating a DpEntry has been "enriched".

Modified: branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/JMapPane.java
===================================================================
--- branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/JMapPane.java	2009-09-30 15:36:39 UTC (rev 419)
+++ branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/JMapPane.java	2009-10-01 20:22:48 UTC (rev 420)
@@ -1018,7 +1018,7 @@
 				if (newArea.getMinX() < maxAllowedExtend.getMinX()) {
 					LOGGER.debug("Now it exeeds the left border.. cut!");
 					// And cut the left if it moved out of the area
-					newArea = new Envelope(new Coordinate(maxExtend.getMinX(),
+					newArea = new Envelope(new Coordinate(maxAllowedExtend.getMinX(),
 							newArea.getMinY()), new Coordinate(newArea
 							.getMaxX(), newArea.getMaxY()));
 

Modified: branches/1.0-gt2-2.6/src/schmitzm/geotools/feature/FeatureUtil.java
===================================================================
--- branches/1.0-gt2-2.6/src/schmitzm/geotools/feature/FeatureUtil.java	2009-09-30 15:36:39 UTC (rev 419)
+++ branches/1.0-gt2-2.6/src/schmitzm/geotools/feature/FeatureUtil.java	2009-10-01 20:22:48 UTC (rev 420)
@@ -29,7 +29,6 @@
  ******************************************************************************/
 package schmitzm.geotools.feature;
 
-
 import java.awt.Color;
 import java.io.IOException;
 import java.math.BigDecimal;
@@ -50,6 +49,8 @@
 import java.util.Vector;
 
 import org.apache.log4j.Logger;
+import org.geotools.coverage.grid.GridCoverage2D;
+import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
 import org.geotools.data.DataUtilities;
 import org.geotools.data.FeatureSource;
 import org.geotools.data.memory.MemoryDataStore;
@@ -61,17 +62,20 @@
 import org.geotools.feature.FeatureCollection;
 import org.geotools.feature.FeatureIterator;
 import org.geotools.feature.GeometryAttributeType;
+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.filter.FilterFactory;
 import org.geotools.map.MapLayer;
+import org.geotools.resources.coverage.FeatureUtilities;
 import org.geotools.styling.Graphic;
 import org.geotools.styling.Mark;
 import org.geotools.styling.Style;
 import org.geotools.styling.StyleBuilder;
 import org.geotools.styling.Symbolizer;
 import org.geotools.util.SimpleInternationalString;
+import org.opengis.coverage.grid.GridCoverageReader;
 import org.opengis.feature.IllegalAttributeException;
 import org.opengis.feature.simple.SimpleFeature;
 import org.opengis.feature.simple.SimpleFeatureType;
@@ -79,6 +83,7 @@
 import org.opengis.feature.type.GeometryDescriptor;
 import org.opengis.filter.Filter;
 import org.opengis.filter.FilterFactory2;
+import org.opengis.parameter.GeneralParameterValue;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 
 import schmitzm.geotools.FilterUtil;
@@ -94,103 +99,123 @@
 import com.vividsolutions.jts.geom.Point;
 import com.vividsolutions.jts.geom.Polygon;
 
-
 /**
  * Diese Klasse beinhaltet statische Methoden zum Arbeiten mit Features.
- *
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * 
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *         (University of Bonn/Germany)
  * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
  * @version 1.1
  */
 public class FeatureUtil {
-  /** {@link ResourceProvider}, der die Lokalisation fuer Komponenten
-   *  des Package {@code schmitzm.geotools.feature} zur Verfuegung stellt. Diese sind
-   *  in properties-Dateien unter {@code schmitzm.geotools.feature.resource.locales}
-   *  hinterlegt. */
-  public static ResourceProvider RESOURCE = new ResourceProvider( LangUtil.extendPackagePath(FeatureUtil.class,"resource.locales.FeatureResourceBundle"), Locale.ENGLISH );
+	/**
+	 * {@link ResourceProvider}, der die Lokalisation fuer Komponenten des
+	 * Package {@code schmitzm.geotools.feature} zur Verfuegung stellt. Diese
+	 * sind in properties-Dateien unter {@code
+	 * schmitzm.geotools.feature.resource.locales} hinterlegt.
+	 */
+	public static ResourceProvider RESOURCE = new ResourceProvider(LangUtil
+			.extendPackagePath(FeatureUtil.class,
+					"resource.locales.FeatureResourceBundle"), Locale.ENGLISH);
 
-  /**
-   * Convenience method to access the {@link ResourceProvider}.
-   */
-  public static String R(String key, Object... values) {
-    return RESOURCE.getString(key, values);
-  }
+	private static final NameImpl GC_NAME = new NameImpl(
+			"http://www.opengis.net/gml", "GridCoverage");
 
-  private static final Logger LOGGER = LangUtil.createLogger(FeatureUtil.class);
+	/**
+	 * Convenience method to access the {@link ResourceProvider}.
+	 */
+	public static String R(String key, Object... values) {
+		return RESOURCE.getString(key, values);
+	}
 
-  private static final String DEFAULT_VECTOR_STYLE_NAME = "default vector style";
+	private static final Logger LOGGER = LangUtil
+			.createLogger(FeatureUtil.class);
 
-  private static final String DEFAULT_JOIN_ATTR = "OID";
+	private static final String DEFAULT_VECTOR_STYLE_NAME = "default vector style";
 
-  private static StyleBuilder STYLE_BUILDER = new StyleBuilder();
+	private static final String DEFAULT_JOIN_ATTR = "OID";
 
-  /** Instance of JTS-GeometryFactory. */
-  public static final GeometryFactory GEOMETRY_FACTORY = new GeometryFactory();
+	private static StyleBuilder STYLE_BUILDER = new StyleBuilder();
 
-  /** Instance of AttributeTypeFactory. */
-  public static final AttributeTypeFactory ATTRTYPE_FACTORY = AttributeTypeFactory.defaultInstance();
+	/** Instance of JTS-GeometryFactory. */
+	public static final GeometryFactory GEOMETRY_FACTORY = new GeometryFactory();
 
-  /** Instance of {@link FilterFactory}. */
-  public static final org.opengis.filter.FilterFactory FILTER_FACTORY = CommonFactoryFinder.getFilterFactory(GeoTools.getDefaultHints());
-  
-  /** Instance of {@link FilterFactory2}. */
-  public static final FilterFactory2 FILTER_FACTORY2 = CommonFactoryFinder.getFilterFactory2(GeoTools.getDefaultHints());
+	/** Instance of AttributeTypeFactory. */
+	public static final AttributeTypeFactory ATTRTYPE_FACTORY = AttributeTypeFactory
+			.defaultInstance();
 
-  /** Caches the already created {@link SimpleFeatureBuilder SimpleFeatureBuilders}
-   *  for reusing in {@link #createFeature(SimpleFeatureType, String, Object[])}. */
-  private static Map<SimpleFeatureType, SimpleFeatureBuilder> featureBuilderCache = new HashMap<SimpleFeatureType, SimpleFeatureBuilder>();
+	/** Instance of {@link FilterFactory}. */
+	public static final org.opengis.filter.FilterFactory FILTER_FACTORY = CommonFactoryFinder
+			.getFilterFactory(GeoTools.getDefaultHints());
 
-  /** Join-Types. */
-  public static enum JoinType {
-    /** The feature of the left collection is taken into the result, even
-     *  there is no join feature in the right collection. */
-    LEFT_OUTER,
-    /** The feature of the right collection is taken into the result, even
-     *  there is no join feature in the left collection. */
-    RIGHT_OUTER,
-    /** Only features with a join feature in the other collection are
-     *  taken into the result (Default). */
-    FULL
-  }
+	/** Instance of {@link FilterFactory2}. */
+	public static final FilterFactory2 FILTER_FACTORY2 = CommonFactoryFinder
+			.getFilterFactory2(GeoTools.getDefaultHints());
 
-  /** The geometry type of a {@link FeatureCollection} */
-  public static enum GeometryForm {
-    /** Point */
-    POINT,
-    /** Line or LineString */
-    LINE,
-    /** Polygon */
-    POLYGON
-  }
+	/**
+	 * Caches the already created {@link SimpleFeatureBuilder
+	 * SimpleFeatureBuilders} for reusing in
+	 * {@link #createFeature(SimpleFeatureType, String, Object[])}.
+	 */
+	private static Map<SimpleFeatureType, SimpleFeatureBuilder> featureBuilderCache = new HashMap<SimpleFeatureType, SimpleFeatureBuilder>();
 
-  /**
-   * Enthaelt die {@link AttributeDescriptor AttributeTypes}, fuer die
-   * automatisch Werte generiert werden koennen.
-   */
-  private static HashMap<AttributeDescriptor, AutoValueGenerator> autoAttrValueGenerators = new HashMap<AttributeDescriptor, AutoValueGenerator>();
+	/** Join-Types. */
+	public static enum JoinType {
+		/**
+		 * The feature of the left collection is taken into the result, even
+		 * there is no join feature in the right collection.
+		 */
+		LEFT_OUTER,
+		/**
+		 * The feature of the right collection is taken into the result, even
+		 * there is no join feature in the left collection.
+		 */
+		RIGHT_OUTER,
+		/**
+		 * Only features with a join feature in the other collection are taken
+		 * into the result (Default).
+		 */
+		FULL
+	}
 
-  /**
-   * Determines the kind of geometry of a {@link SimpleFeatureType}.
-   * @param fType a feature type
-   */
-  public static GeometryForm getGeometryForm(SimpleFeatureType fType) {
-    if ( fType.getGeometryDescriptor() == null )
-      return null;
-    
-    GeometryDescriptor geometryType = fType.getGeometryDescriptor();
-	return getGeometryForm(geometryType);
-  }
-  
+	/** The geometry type of a {@link FeatureCollection} */
+	public static enum GeometryForm {
+		/** Point */
+		POINT,
+		/** Line or LineString */
+		LINE,
+		/** Polygon */
+		POLYGON
+	}
 
-  /**
-   * Determines the kind of geometry of a {@link GeometryDescriptor}.
-   */
-  public static GeometryForm getGeometryForm(GeometryDescriptor gDesc) {
-	return getGeometryForm(gDesc.getType().getBinding());
-  }
+	/**
+	 * Enthaelt die {@link AttributeDescriptor AttributeTypes}, fuer die
+	 * automatisch Werte generiert werden koennen.
+	 */
+	private static HashMap<AttributeDescriptor, AutoValueGenerator> autoAttrValueGenerators = new HashMap<AttributeDescriptor, AutoValueGenerator>();
 
+	/**
+	 * Determines the kind of geometry of a {@link SimpleFeatureType}.
+	 * 
+	 * @param fType
+	 *            a feature type
+	 */
+	public static GeometryForm getGeometryForm(SimpleFeatureType fType) {
+		if (fType.getGeometryDescriptor() == null)
+			return null;
 
-  /**
+		GeometryDescriptor geometryType = fType.getGeometryDescriptor();
+		return getGeometryForm(geometryType);
+	}
+
+	/**
+	 * Determines the kind of geometry of a {@link GeometryDescriptor}.
+	 */
+	public static GeometryForm getGeometryForm(GeometryDescriptor gDesc) {
+		return getGeometryForm(gDesc.getType().getBinding());
+	}
+
+	/**
 	 * Determines the kind of geometry of a {@link GeometryAttributeType}.
 	 * 
 	 * @param geometryType
@@ -202,7 +227,6 @@
 		return getGeometryForm(geometryType.getBinding());
 	}
 
-
 	/**
 	 * Determines the kind of geometry of a {@link Class}.
 	 */
@@ -222,1152 +246,1492 @@
 				+ geometryType.getName());
 	}
 
-  /**
-   * Determines the kind of geometry of a {@link FeatureCollection}.
-   * @param fc a feature collection
-   */
-  public static GeometryForm getGeometryForm(FeatureCollection<SimpleFeatureType, SimpleFeature> fc) {
-    return getGeometryForm(fc.getSchema());
-  }
+	/**
+	 * Determines the kind of geometry of a {@link FeatureCollection}.
+	 * 
+	 * @param fc
+	 *            a feature collection
+	 */
+	public static GeometryForm getGeometryForm(
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fc) {
+		return getGeometryForm(fc.getSchema());
+	}
 
-  /**
-   * Determines the kind of geometry of a {@link FeatureSource}.
-   * @param fs a feature source
-   */
-  public static GeometryForm getGeometryForm(FeatureSource<SimpleFeatureType, SimpleFeature> fs) {
-    return getGeometryForm(fs.getSchema());
-  }
+	/**
+	 * Determines the kind of geometry of a {@link FeatureSource}.
+	 * 
+	 * @param fs
+	 *            a feature source
+	 */
+	public static GeometryForm getGeometryForm(
+			FeatureSource<SimpleFeatureType, SimpleFeature> fs) {
+		return getGeometryForm(fs.getSchema());
+	}
 
-  /**
-   * Determines the kind of geometry of a {@link MapLayer}. 
-   * @param layer a map layer
-   */
-  public static GeometryForm getGeometryForm(MapLayer layer) {
-    return getGeometryForm((SimpleFeatureType) layer.getFeatureSource());
-  }
+	/**
+	 * Determines the kind of geometry of a {@link MapLayer}.
+	 * 
+	 * @param layer
+	 *            a map layer
+	 */
+	public static GeometryForm getGeometryForm(MapLayer layer) {
+		return getGeometryForm((SimpleFeatureType) layer.getFeatureSource());
+	}
 
-    /**
-   * Extrahiert alle Geometrien aus einem SimpleFeature.
-   * @param f SimpleFeature
-   * @return Array aller Geometrien im SimpleFeature.
-   */
-  public static Geometry[] extractGeometriesToGeometry(SimpleFeature f) {
-    Vector<Object> geomVec = new Vector<Object>();
+	/**
+	 * Extrahiert alle Geometrien aus einem SimpleFeature.
+	 * 
+	 * @param f
+	 *            SimpleFeature
+	 * @return Array aller Geometrien im SimpleFeature.
+	 */
+	public static Geometry[] extractGeometriesToGeometry(SimpleFeature f) {
+		Vector<Object> geomVec = new Vector<Object>();
 
-    for (int j=0; j<f.getFeatureType().getAttributeCount(); j++)
-//      if ( f.getFeatureType().getAttributeType(j).isGeometry() )
-      if ( f.getFeatureType() instanceof GeometryAttributeType )
-        geomVec.add(f.getAttribute(j));
+		for (int j = 0; j < f.getFeatureType().getAttributeCount(); j++)
+			// if ( f.getFeatureType().getAttributeType(j).isGeometry() )
+			if (f.getFeatureType() instanceof GeometryAttributeType)
+				geomVec.add(f.getAttribute(j));
 
-    Geometry[] geomArr = new Geometry[geomVec.size()];
-    for (int i=0; i<geomVec.size(); i++)
-      geomArr[i] = (Geometry)geomVec.elementAt(i);
-    return geomArr;
-  }
+		Geometry[] geomArr = new Geometry[geomVec.size()];
+		for (int i = 0; i < geomVec.size(); i++)
+			geomArr[i] = (Geometry) geomVec.elementAt(i);
+		return geomArr;
+	}
 
-  /**
-   * Extrahiert alle Default-Geometrien aus einer FeatureCollection.
-   * @param fc FeatureCollection
-   * @return Array aller Geometrien in der FeatureCollection.
-   */
-  public static Vector<Geometry> extractGeometries(FeatureCollection<SimpleFeatureType, SimpleFeature> fc, Vector<Geometry> result) {
-    if ( result == null )
-      result = new Vector<Geometry>();
+	/**
+	 * Extrahiert alle Default-Geometrien aus einer FeatureCollection.
+	 * 
+	 * @param fc
+	 *            FeatureCollection
+	 * @return Array aller Geometrien in der FeatureCollection.
+	 */
+	public static Vector<Geometry> extractGeometries(
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fc,
+			Vector<Geometry> result) {
+		if (result == null)
+			result = new Vector<Geometry>();
 
-    FeatureIterator<SimpleFeature> fi = fc.features();
-    for (;fi.hasNext();) {
-      SimpleFeature f = fi.next();
-      result.add( (Geometry) f.getDefaultGeometry() );
-    }
-    return result;
-  }
+		FeatureIterator<SimpleFeature> fi = fc.features();
+		for (; fi.hasNext();) {
+			SimpleFeature f = fi.next();
+			result.add((Geometry) f.getDefaultGeometry());
+		}
+		return result;
+	}
 
-  /**
-   * Erzeugt einen Standard-Style fuer eine {@link FeatureCollection}
-   * Und setzt eine default namen
-   * @param fc FeatureCollection
-   */
-  public static Style createDefaultStyle(FeatureCollection<SimpleFeatureType, SimpleFeature> fc) {
-    return createDefaultStyle( fc.getSchema().getGeometryDescriptor() );
-  }
+	/**
+	 * Erzeugt einen Standard-Style fuer eine {@link FeatureCollection} Und
+	 * setzt eine default namen
+	 * 
+	 * @param fc
+	 *            FeatureCollection
+	 */
+	public static Style createDefaultStyle(
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fc) {
+		return createDefaultStyle(fc.getSchema().getGeometryDescriptor());
+	}
 
-  /**
-   * Erzeugt einen Standard-Style fuer einen {@link GeometryAttributeType}
-   * Und setzt eine default Namen.
-   * @param geometryAttrib GeometryAttributeType
-   */
-  public static Style createDefaultStyle(GeometryDescriptor geometryAttrib) {
-    Style style = null;
+	/**
+	 * Erzeugt einen Standard-Style fuer einen {@link GeometryAttributeType} Und
+	 * setzt eine default Namen.
+	 * 
+	 * @param geometryAttrib
+	 *            GeometryAttributeType
+	 */
+	public static Style createDefaultStyle(GeometryDescriptor geometryAttrib) {
+		Style style = null;
 
-    if ( geometryAttrib != null &&
-        (com.vividsolutions.jts.geom.Polygon.class.isAssignableFrom(geometryAttrib.getType().getBinding()) ||
-         com.vividsolutions.jts.geom.MultiPolygon.class.isAssignableFrom(geometryAttrib.getType().getBinding())) )
-     style = createPolygonStyle(Color.ORANGE, Color.BLACK, 1);
-    else if (geometryAttrib != null &&
-             (com.vividsolutions.jts.geom.Point.class.isAssignableFrom(geometryAttrib.getType().getBinding()) ||
-              com.vividsolutions.jts.geom.MultiPoint.class.isAssignableFrom(geometryAttrib.getType().getBinding())) )
-      style = createPointStyle(Color.RED);
-    else
-      style = createLineStyle(Color.BLUE, 1);
+		if (geometryAttrib != null
+				&& (com.vividsolutions.jts.geom.Polygon.class
+						.isAssignableFrom(geometryAttrib.getType().getBinding()) || com.vividsolutions.jts.geom.MultiPolygon.class
+						.isAssignableFrom(geometryAttrib.getType().getBinding())))
+			style = createPolygonStyle(Color.ORANGE, Color.BLACK, 1);
+		else if (geometryAttrib != null
+				&& (com.vividsolutions.jts.geom.Point.class
+						.isAssignableFrom(geometryAttrib.getType().getBinding()) || com.vividsolutions.jts.geom.MultiPoint.class
+						.isAssignableFrom(geometryAttrib.getType().getBinding())))
+			style = createPointStyle(Color.RED);
+		else
+			style = createLineStyle(Color.BLUE, 1);
 
-    style.setName(DEFAULT_VECTOR_STYLE_NAME);
-    
-//    26 style.setTitle(DEFAULT_VECTOR_STYLE_NAME);
-    style.getDescription().setTitle( new SimpleInternationalString( DEFAULT_VECTOR_STYLE_NAME) );
-    return style;
-  }
+		style.setName(DEFAULT_VECTOR_STYLE_NAME);
 
-  /**
-   * Erzeugt einen Polygon-Style.
-   * @param fillColor Fuell-Farbe
-   * @param borderColor Rand-Farbe
-   * @param borderWidth Breite des Rands
-   */
-  public static Style createPolygonStyle(Color fillColor, Color borderColor, double borderWidth) {
-    final Symbolizer symb = STYLE_BUILDER.createPolygonSymbolizer(fillColor, borderColor, borderWidth);
-    return STYLE_BUILDER.createStyle( symb );
-  }
+		// 26 style.setTitle(DEFAULT_VECTOR_STYLE_NAME);
+		style.getDescription().setTitle(
+				new SimpleInternationalString(DEFAULT_VECTOR_STYLE_NAME));
+		return style;
+	}
 
-  /**
-   * Erzeugt einen (randlosen) Punkt-Style in Form eines Kreises.
-   * @param color Farbe des Punkts
-   */
-  public static Style createPointStyle(Color fillColor) {
-    return createPointStyle(fillColor, fillColor, 5);
-  }
+	/**
+	 * Erzeugt einen Polygon-Style.
+	 * 
+	 * @param fillColor
+	 *            Fuell-Farbe
+	 * @param borderColor
+	 *            Rand-Farbe
+	 * @param borderWidth
+	 *            Breite des Rands
+	 */
+	public static Style createPolygonStyle(Color fillColor, Color borderColor,
+			double borderWidth) {
+		final Symbolizer symb = STYLE_BUILDER.createPolygonSymbolizer(
+				fillColor, borderColor, borderWidth);
+		return STYLE_BUILDER.createStyle(symb);
+	}
 
-  /**
-   * Erzeugt einen (randlosen) Punkt-Style in Form eines Kreises.
-   * @param fillColor Fuell-Farbe des Punkts
-   * @param borderColor Rand-Farbe des Punkts
-   * @param width Groesse des Punkts
-   */
-  public static Style createPointStyle(Color fillColor, Color borderColor, double width) {
-    return createPointStyle(StyleBuilder.MARK_CIRCLE, fillColor, borderColor, 1, 1, width, 0);
-  }
+	/**
+	 * Erzeugt einen (randlosen) Punkt-Style in Form eines Kreises.
+	 * 
+	 * @param color
+	 *            Farbe des Punkts
+	 */
+	public static Style createPointStyle(Color fillColor) {
+		return createPointStyle(fillColor, fillColor, 5);
+	}
 
-  /**
-   * Erzeugt einen Punkt-Style.
-   * @param color Farbe des Punkts
-   * @param markStyle Darstellungsweise des Punkts
-   * @param opacity
-   * @see StyleBuilder#MARK_ARROW;
-   * @see StyleBuilder#MARK_CIRCLE;
-   * @see StyleBuilder#MARK_CROSS;
-   * @see StyleBuilder#MARK_SQUARE;
-   * @see StyleBuilder#MARK_STAR;
-   * @see StyleBuilder#MARK_TRIANGLE;
-   * @see StyleBuilder#MARK_X;
-   */
-  public static Style createPointStyle(String markStyle, Color fillColor, Color borderColor, double borderWidth, double opacity, double size, double rotation) {
-    final Mark       mark = STYLE_BUILDER.createMark(markStyle, fillColor, borderColor, borderWidth);
-    final Graphic    g    = STYLE_BUILDER.createGraphic(null, mark, null, opacity, size, rotation);
-    final Symbolizer symb = STYLE_BUILDER.createPointSymbolizer(g);
-    return STYLE_BUILDER.createStyle( symb );
-  }
+	/**
+	 * Erzeugt einen (randlosen) Punkt-Style in Form eines Kreises.
+	 * 
+	 * @param fillColor
+	 *            Fuell-Farbe des Punkts
+	 * @param borderColor
+	 *            Rand-Farbe des Punkts
+	 * @param width
+	 *            Groesse des Punkts
+	 */
+	public static Style createPointStyle(Color fillColor, Color borderColor,
+			double width) {
+		return createPointStyle(StyleBuilder.MARK_CIRCLE, fillColor,
+				borderColor, 1, 1, width, 0);
+	}
 
-  /**
-   * Erzeugt einen Linien-Style.
-   * @param lineColor Farbe der Linie
-   */
-  public static Style createLineStyle(Color lineColor) {
-    return createLineStyle(lineColor, 1);
-  }
+	/**
+	 * Erzeugt einen Punkt-Style.
+	 * 
+	 * @param color
+	 *            Farbe des Punkts
+	 * @param markStyle
+	 *            Darstellungsweise des Punkts
+	 * @param opacity
+	 * @see StyleBuilder#MARK_ARROW;
+	 * @see StyleBuilder#MARK_CIRCLE;
+	 * @see StyleBuilder#MARK_CROSS;
+	 * @see StyleBuilder#MARK_SQUARE;
+	 * @see StyleBuilder#MARK_STAR;
+	 * @see StyleBuilder#MARK_TRIANGLE;
+	 * @see StyleBuilder#MARK_X;
+	 */
+	public static Style createPointStyle(String markStyle, Color fillColor,
+			Color borderColor, double borderWidth, double opacity, double size,
+			double rotation) {
+		final Mark mark = STYLE_BUILDER.createMark(markStyle, fillColor,
+				borderColor, borderWidth);
+		final Graphic g = STYLE_BUILDER.createGraphic(null, mark, null,
+				opacity, size, rotation);
+		final Symbolizer symb = STYLE_BUILDER.createPointSymbolizer(g);
+		return STYLE_BUILDER.createStyle(symb);
+	}
 
-  /**
-   * Erzeugt einen Linien-Style.
-   * @param lineColor Farbe der Linie
-   * @param lineWidth Breite der Linie
-   */
-  public static Style createLineStyle(Color lineColor, double lineWidth) {
-    // TODO I don't like StyleBuilder!
-    final Symbolizer symb = STYLE_BUILDER.createLineSymbolizer(lineColor, lineWidth);
-    return STYLE_BUILDER.createStyle( symb );
-  }
+	/**
+	 * Erzeugt einen Linien-Style.
+	 * 
+	 * @param lineColor
+	 *            Farbe der Linie
+	 */
+	public static Style createLineStyle(Color lineColor) {
+		return createLineStyle(lineColor, 1);
+	}
 
+	/**
+	 * Erzeugt einen Linien-Style.
+	 * 
+	 * @param lineColor
+	 *            Farbe der Linie
+	 * @param lineWidth
+	 *            Breite der Linie
+	 */
+	public static Style createLineStyle(Color lineColor, double lineWidth) {
+		// TODO I don't like StyleBuilder!
+		final Symbolizer symb = STYLE_BUILDER.createLineSymbolizer(lineColor,
+				lineWidth);
+		return STYLE_BUILDER.createStyle(symb);
+	}
 
- /**
-  * Erzeugt einen Array von {@link SimpleFeature Features} auf einer
-  * {@link FeatureCollection}.<br>
-  * Aufgrund von Problemen bei der Verwendung von Filtern ({@code .size()} liefert
-  * nicht die Anzahl der gefilterten Features; {@code .toArray} liefert
-  * manchmal {@code null}), wird der Array "naiv" ueber Durchlaufen
-  * eines {@link FeatureIterator} kopiert.
-  * @param fc eine SimpleFeature Collection
-  * @return einen leeren Array, wenn die Collection leer oder {@code null} ist
-  */
-  public static SimpleFeature[] featuresToArray(FeatureCollection<SimpleFeatureType, SimpleFeature> fc) {
-//    if ( fc == null || fc.size() == 0 ) // bei leerer FC klappt .toArray nicht!!
-//      return new SimpleFeature[0];
-//    SimpleFeature[] featureArray = (SimpleFeature[])fc.toArray(new SimpleFeature[0]);
-//    if ( featureArray != null )
-//      return featureArray;
-//    // Sonst "naiv" kopieren
-//    featureArray = new SimpleFeature[fc.size()];
-//    FeatureIterator fi = fc.features();
-//    for (int i=0; fi.hasNext(); i++)
-//      featureArray[i] = fi.next();
-//    return featureArray;
-      return featuresToArray(fc,true);
-  }
+	/**
+	 * Erzeugt einen Array von {@link SimpleFeature Features} auf einer
+	 * {@link FeatureCollection}.<br>
+	 * Aufgrund von Problemen bei der Verwendung von Filtern ({@code .size()}
+	 * liefert nicht die Anzahl der gefilterten Features; {@code .toArray}
+	 * liefert manchmal {@code null}), wird der Array "naiv" ueber Durchlaufen
+	 * eines {@link FeatureIterator} kopiert.
+	 * 
+	 * @param fc
+	 *            eine SimpleFeature Collection
+	 * @return einen leeren Array, wenn die Collection leer oder {@code null}
+	 *         ist
+	 */
+	public static SimpleFeature[] featuresToArray(
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fc) {
+		// if ( fc == null || fc.size() == 0 ) // bei leerer FC klappt .toArray
+		// nicht!!
+		// return new SimpleFeature[0];
+		// SimpleFeature[] featureArray = (SimpleFeature[])fc.toArray(new
+		// SimpleFeature[0]);
+		// if ( featureArray != null )
+		// return featureArray;
+		// // Sonst "naiv" kopieren
+		// featureArray = new SimpleFeature[fc.size()];
+		// FeatureIterator fi = fc.features();
+		// for (int i=0; fi.hasNext(); i++)
+		// featureArray[i] = fi.next();
+		// return featureArray;
+		return featuresToArray(fc, true);
+	}
 
-  /**
-   * Erzeugt einen Array von {@link SimpleFeature Features} auf einer
-   * {@link FeatureCollection}.
-   * @param fc
-   *            eine SimpleFeature Collection
-   * @param
-   *        includeNullFeatures
-   *            wenn {@code false} werden NULL-Features in der Collection nicht in den
-   *            Array kopiert
-   * @return einen leeren Array, wenn die Collection leer oder {@code null} ist
-   */
-   public static SimpleFeature[] featuresToArray(FeatureCollection<SimpleFeatureType, SimpleFeature> fc, boolean includeNullFeatures) {
-//     if ( includeNullFeatures )
-//       return featuresToArray(fc);
-     if ( fc == null )
-       return new SimpleFeature[0];
-     
-     // Naiv alle Features durchgehen.
-     Vector<SimpleFeature> fv = new Vector<SimpleFeature>();
-     FeatureIterator<SimpleFeature> fi = fc.features();
-     for (int i=0; fi.hasNext(); i++) {
-       SimpleFeature f = fi.next();
-       if ( includeNullFeatures || f != null )
-         fv.add(f);
-     }
-     return fv.toArray(new SimpleFeature[0]);
-   }
+	/**
+	 * Erzeugt einen Array von {@link SimpleFeature Features} auf einer
+	 * {@link FeatureCollection}.
+	 * 
+	 * @param fc
+	 *            eine SimpleFeature Collection
+	 * @param includeNullFeatures
+	 *            wenn {@code false} werden NULL-Features in der Collection
+	 *            nicht in den Array kopiert
+	 * @return einen leeren Array, wenn die Collection leer oder {@code null}
+	 *         ist
+	 */
+	public static SimpleFeature[] featuresToArray(
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fc,
+			boolean includeNullFeatures) {
+		// if ( includeNullFeatures )
+		// return featuresToArray(fc);
+		if (fc == null)
+			return new SimpleFeature[0];
 
-   /**
-   * Clones an {@link SimpleFeatureType}.
-   * @param fType     type to clone
-   * @param fTypeName the name for the clone (if {@code null} the name is
-   *                  taken from {@code fType})
-   * @param nillable  nillable property for <b>all</b> attributes (if {@code null} the
-   *                  nillable property is taken individually from the source attributes)
-   */
-  public static SimpleFeatureType cloneFeatureType(SimpleFeatureType fType, String fTypeName, Boolean nillable) throws SchemaException {
-    if ( fTypeName == null )
-      fTypeName = fType.getTypeName();
+		// Naiv alle Features durchgehen.
+		Vector<SimpleFeature> fv = new Vector<SimpleFeature>();
+		FeatureIterator<SimpleFeature> fi = fc.features();
+		for (int i = 0; fi.hasNext(); i++) {
+			SimpleFeature f = fi.next();
+			if (includeNullFeatures || f != null)
+				fv.add(f);
+		}
+		return fv.toArray(new SimpleFeature[0]);
+	}
 
-    SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
-    builder.setName(fType.getTypeName());
-    for (AttributeDescriptor aType : fType.getAttributeDescriptors() ) {
-      AttributeDescriptor aTypeClone = cloneAttributeType(aType, nillable);
-      builder.add(aTypeClone);
-      if ( aTypeClone instanceof GeometryAttributeType && builder.getDefaultGeometry() == null )
-        builder.setDefaultGeometry( aTypeClone.getLocalName() );
-    }
-    return builder.buildFeatureType();
-  }
+	/**
+	 * Clones an {@link SimpleFeatureType}.
+	 * 
+	 * @param fType
+	 *            type to clone
+	 * @param fTypeName
+	 *            the name for the clone (if {@code null} the name is taken from
+	 *            {@code fType})
+	 * @param nillable
+	 *            nillable property for <b>all</b> attributes (if {@code null}
+	 *            the nillable property is taken individually from the source
+	 *            attributes)
+	 */
+	public static SimpleFeatureType cloneFeatureType(SimpleFeatureType fType,
+			String fTypeName, Boolean nillable) throws SchemaException {
+		if (fTypeName == null)
+			fTypeName = fType.getTypeName();
 
-  /**
-   * Clones an {@link AttributeDescriptor}.
-   * @param aType type to clone
-   * @param nillable the clone gets this value for its nillable property independently
-   *                 of {@code aType.isNillable()} (if {@code null} the nillable property
-   *                 is taken from {@code aType})
-   *
-   */
-  public static AttributeDescriptor cloneAttributeType(AttributeDescriptor aType, Boolean nillable) {
-    // If no special nillable property is specified, take it from the
-    // given AttributeDescriptor
-    if ( nillable == null )
-      nillable = aType.isNillable();
+		SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
+		builder.setName(fType.getTypeName());
+		for (AttributeDescriptor aType : fType.getAttributeDescriptors()) {
+			AttributeDescriptor aTypeClone = cloneAttributeType(aType, nillable);
+			builder.add(aTypeClone);
+			if (aTypeClone instanceof GeometryAttributeType
+					&& builder.getDefaultGeometry() == null)
+				builder.setDefaultGeometry(aTypeClone.getLocalName());
+		}
+		return builder.buildFeatureType();
+	}
 
-    // Create a default value for the attribute
-    Object defaultValue = nillable ? null : getDefaultAttributeValue(aType);
+	/**
+	 * Clones an {@link AttributeDescriptor}.
+	 * 
+	 * @param aType
+	 *            type to clone
+	 * @param nillable
+	 *            the clone gets this value for its nillable property
+	 *            independently of {@code aType.isNillable()} (if {@code null}
+	 *            the nillable property is taken from {@code aType})
+	 * 
+	 */
+	public static AttributeDescriptor cloneAttributeType(
+			AttributeDescriptor aType, Boolean nillable) {
+		// If no special nillable property is specified, take it from the
+		// given AttributeDescriptor
+		if (nillable == null)
+			nillable = aType.isNillable();
 
-    Object metaData = null;
-    // if it is a GeometryAttributeType, the CRS must be stored
-    // in the meta data
-    if ( aType instanceof GeometryAttributeType )
-      metaData = ((GeometryAttributeType)aType).getCoordinateSystem();
+		// Create a default value for the attribute
+		Object defaultValue = nillable ? null : getDefaultAttributeValue(aType);
 
-    // combine the restrictions of the attribute type for the
-    // AttributeTypeFactory
-    Filter restrictions = FilterUtil.FILTER_FAC.and( aType.getType().getRestrictions() );
-    
-    // Create the clone
-    return AttributeTypeFactory.newAttributeType(
-            aType.getLocalName(),
-            aType.getType().getBinding(),
-            nillable,
-            restrictions,
-            defaultValue,
-            metaData
-           );
-  }
+		Object metaData = null;
+		// if it is a GeometryAttributeType, the CRS must be stored
+		// in the meta data
+		if (aType instanceof GeometryAttributeType)
+			metaData = ((GeometryAttributeType) aType).getCoordinateSystem();
 
-  /**
-   * Erweitert das Schema einer {@link FeatureCollection} um eine Reihe von
-   * Attributen.
-   * @param fType  zu erweiterndes SimpleFeature-Schema
-   * @param aTypes Typen der neuen Attribute
-   * @return eine <b>neue</b> Instanz von {@link SimpleFeatureType}
-   * @throws SchemaException falls das Erweitern des SimpleFeature-Schemas scheitert
-   * @throws NullPointerException falls {@code fType = null}
-   */
-  public static SimpleFeatureType extendFeatureType(SimpleFeatureType fType, List<AttributeDescriptor> aTypes) throws SchemaException {
-    return extendFeatureType(fType, aTypes.toArray(new AttributeDescriptor[0]));
-  }
-  
-  /**
-   * Erweitert das Schema einer {@link FeatureCollection} um eine Reihe von
-   * Attributen.
-   * @param fType  zu erweiterndes SimpleFeature-Schema
-   * @param aTypes Typen der neuen Attribute
-   * @return eine <b>neue</b> Instanz von {@link SimpleFeatureType}
-   * @throws SchemaException falls das Erweitern des SimpleFeature-Schemas scheitert
-   * @throws NullPointerException falls {@code fType = null}
-   */
-  public static SimpleFeatureType extendFeatureType(SimpleFeatureType fType, AttributeDescriptor... aTypes) throws SchemaException {
-//BEMERKUNG: Folgende Methode funktioniert, fuegt die abgeleiteten (alten)
-//           Attribute aber hinten an die neuen Attribute an. Dies ist
-//           nicht gewuenscht und erschwert auch den Aufbau des fValues-Array
-//    SimpleFeatureType resultType = FeatureTypeBuilder.newFeatureType(
-//        aTypes,                    // new Attributes
-//        fType.getTypeName(),       // new type name
-//        null,                      // namespace
-//        false,                     // abstact?
-//        new SimpleFeatureType[] { fType },
-//        null
-//    );
+		// combine the restrictions of the attribute type for the
+		// AttributeTypeFactory
+		Filter restrictions = FilterUtil.FILTER_FAC.and(aType.getType()
+				.getRestrictions());
 
-    SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
-    builder.setName( fType.getName() );
-    builder.addAll( fType.getAttributeDescriptors() ); // old attributes
-    for (AttributeDescriptor aType : aTypes ) {
-      // combine the restrictions of the attribute type for the
-      // AttributeTypeFactory
-      Filter restrictions = FilterUtil.FILTER_FAC.and( aType.getType().getRestrictions() );
+		// Create the clone
+		return AttributeTypeFactory.newAttributeType(aType.getLocalName(),
+				aType.getType().getBinding(), nillable, restrictions,
+				defaultValue, metaData);
+	}
 
-      try {
-        builder.add(aType);
-        if ( aType instanceof GeometryAttributeType && builder.getDefaultGeometry() == null )
-          builder.setDefaultGeometry( aType.getLocalName() );
-      } catch (IllegalArgumentException err) {
-        builder.add( AttributeTypeFactory.newAttributeType(
-            aType.getLocalName()+"_2",
-            aType.getType().getBinding(),
-            aType.isNillable(),
-            restrictions,
-            aType.getDefaultValue(),
-            null
-        ));
-      }
-    }
-    SimpleFeatureType resultType = builder.buildFeatureType();
+	/**
+	 * Erweitert das Schema einer {@link FeatureCollection} um eine Reihe von
+	 * Attributen.
+	 * 
+	 * @param fType
+	 *            zu erweiterndes SimpleFeature-Schema
+	 * @param aTypes
+	 *            Typen der neuen Attribute
+	 * @return eine <b>neue</b> Instanz von {@link SimpleFeatureType}
+	 * @throws SchemaException
+	 *             falls das Erweitern des SimpleFeature-Schemas scheitert
+	 * @throws NullPointerException
+	 *             falls {@code fType = null}
+	 */
+	public static SimpleFeatureType extendFeatureType(SimpleFeatureType fType,
+			List<AttributeDescriptor> aTypes) throws SchemaException {
+		return extendFeatureType(fType, aTypes
+				.toArray(new AttributeDescriptor[0]));
+	}
 
-    // As long as DataUtilities.defaultValue(AttributeDescriptor) does
-    // not handle the default value correctly for not-nillable
-    // attributes, create a new SimpleFeatureType with all attributes
-    // nillable
-// not necessary as long a correct default value can be created
-// in createFeatureType(ResultSetMetaData, ...)
-//    resultType = cloneFeatureType(resultType, null, true);
+	/**
+	 * Erweitert das Schema einer {@link FeatureCollection} um eine Reihe von
+	 * Attributen.
+	 * 
+	 * @param fType
+	 *            zu erweiterndes SimpleFeature-Schema
+	 * @param aTypes
+	 *            Typen der neuen Attribute
+	 * @return eine <b>neue</b> Instanz von {@link SimpleFeatureType}
+	 * @throws SchemaException
+	 *             falls das Erweitern des SimpleFeature-Schemas scheitert
+	 * @throws NullPointerException
+	 *             falls {@code fType = null}
+	 */
+	public static SimpleFeatureType extendFeatureType(SimpleFeatureType fType,
+			AttributeDescriptor... aTypes) throws SchemaException {
+		// BEMERKUNG: Folgende Methode funktioniert, fuegt die abgeleiteten
+		// (alten)
+		// Attribute aber hinten an die neuen Attribute an. Dies ist
+		// nicht gewuenscht und erschwert auch den Aufbau des fValues-Array
+		// SimpleFeatureType resultType = FeatureTypeBuilder.newFeatureType(
+		// aTypes, // new Attributes
+		// fType.getTypeName(), // new type name
+		// null, // namespace
+		// false, // abstact?
+		// new SimpleFeatureType[] { fType },
+		// null
+		// );
 
-    return resultType;
-  }
-  
-  /**
-   * Orderes {@link SimpleFeature Features} according to an attribute (ascending). 
-   * @param fi       the features to order
-   * @param attrName the attribute to order by
-   * @return a list of ordered features
-   */
-  public static Vector<SimpleFeature> sortFeatures(FeatureCollection<SimpleFeatureType, SimpleFeature> fc, String attrName) {
-    return sortFeatures(fc.features(), attrName);
-  }
+		SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
+		builder.setName(fType.getName());
+		builder.addAll(fType.getAttributeDescriptors()); // old attributes
+		for (AttributeDescriptor aType : aTypes) {
+			// combine the restrictions of the attribute type for the
+			// AttributeTypeFactory
+			Filter restrictions = FilterUtil.FILTER_FAC.and(aType.getType()
+					.getRestrictions());
 
-  /**
-   * Orderes {@link SimpleFeature Features} according to an attribute (ascending). 
-   * @param fi       an iterator for the features
-   * @param attrName the attribute to order by
-   * @return a list of ordered features
-   */
-  public static Vector<SimpleFeature> sortFeatures(FeatureIterator<SimpleFeature> fi, String attrName) {
-    // First create a SortedMap with CollisionList
-    SortedMap<Comparable<?>, Vector<SimpleFeature>> sortedFeatureLists = new TreeMap<Comparable<?>, Vector<SimpleFeature>>();
-    for (;fi.hasNext();) {
-      SimpleFeature f = fi.next();
-      // Check whether attribute value is Comparable
-      Object attrValue  = f.getAttribute(attrName);
-      if ( attrValue != null && !(attrValue instanceof Comparable) )
-        throw new UnsupportedOperationException("SimpleFeature sort only supported for Comparable attributes: "+LangUtil.getSimpleClassName(attrValue));
-      // Determine X value as sort attribute (NULL not permitted for XYDateset!)
-      Comparable<?> xValue = (Comparable<?>)attrValue;
-      if ( xValue == null )
-        continue;
-      
-      // Check whether collision list exists
-      Vector<SimpleFeature> collList = sortedFeatureLists.get(xValue);
-      if ( collList == null ) {
-        collList = new Vector<SimpleFeature>();
-        sortedFeatureLists.put(xValue, collList);
-      }
-      // Add feature to collision list
-      collList.add(f);
-    }
-    
-    // Put the (now ordered) features from the collision lists
-    // into an temporary list to create a list of Features
-    Vector<SimpleFeature> sortedFeatures = new Vector<SimpleFeature>();
-    for (Vector<SimpleFeature> collList : sortedFeatureLists.values())
-      for (SimpleFeature f : collList)
-        sortedFeatures.add(f);
+			try {
+				builder.add(aType);
+				if (aType instanceof GeometryAttributeType
+						&& builder.getDefaultGeometry() == null)
+					builder.setDefaultGeometry(aType.getLocalName());
+			} catch (IllegalArgumentException err) {
+				builder.add(AttributeTypeFactory.newAttributeType(aType
+						.getLocalName()
+						+ "_2", aType.getType().getBinding(), aType
+						.isNillable(), restrictions, aType.getDefaultValue(),
+						null));
+			}
+		}
+		SimpleFeatureType resultType = builder.buildFeatureType();
 
-    return sortedFeatures;
-  }
+		// As long as DataUtilities.defaultValue(AttributeDescriptor) does
+		// not handle the default value correctly for not-nillable
+		// attributes, create a new SimpleFeatureType with all attributes
+		// nillable
+		// not necessary as long a correct default value can be created
+		// in createFeatureType(ResultSetMetaData, ...)
+		// resultType = cloneFeatureType(resultType, null, true);
 
-  /**
-   * Erweitert das Schema einer {@link FeatureCollection} um eine Reihe von
-   * Attributen.
-   * @param fc     zu erweiternde FeatureCollection
-   * @param aTypes Typen der neuen Attribute
-   * @return eine <b>neue</b> Instanz von {@link FeatureCollection}
-   * @throws SchemaException falls das Erweitern des SimpleFeature-Schemas scheitert
-   * @throws IllegalAttributeException falls das Einfuegen der Features in die
-   *         neue {@link FeatureCollection} scheitert
-   */
-  public static FeatureCollection<SimpleFeatureType, SimpleFeature> extendFeatureCollection(FeatureCollection<SimpleFeatureType, SimpleFeature> fc, AttributeDescriptor... aTypes) throws SchemaException, IllegalAttributeException  {
-    // Schema erstellen
-    SimpleFeatureType fType = fc.getSchema();
-    SimpleFeatureType resultType = extendFeatureType( fType, aTypes );
+		return resultType;
+	}
 
-    // Neue Collection erstellen
-    FeatureCollection<SimpleFeatureType, SimpleFeature> resultFc = DefaultFeatureCollections.newCollection();
-    FeatureIterator<SimpleFeature>   fi       = fc.features();
-    // Array fuer die Attribut-Werte eines Features
-    
-    List<Object>     fValues  = new ArrayList<Object>(resultType.getAttributeCount());
-    for ( ; fi.hasNext(); ) {
-      // Werte der alten Attribute in Array schreiben
-    	fValues = fi.next().getAttributes();
-      
-      // Default-Werte der neuen Attribute in Array schreiben
-      for ( int i=fType.getAttributeCount(); i<fValues.size(); i++)
-        fValues.set(i,resultType.getAttributeDescriptors().get(i).getDefaultValue());
-      // Erweitertes SimpleFeature erzeugen und FeatureCollection fuellen
-      resultFc.add( createFeature(resultType,fValues ) );
-    }
+	/**
+	 * Orderes {@link SimpleFeature Features} according to an attribute
+	 * (ascending).
+	 * 
+	 * @param fi
+	 *            the features to order
+	 * @param attrName
+	 *            the attribute to order by
+	 * @return a list of ordered features
+	 */
+	public static Vector<SimpleFeature> sortFeatures(
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fc,
+			String attrName) {
+		return sortFeatures(fc.features(), attrName);
+	}
 
-    return resultFc;
-  }
+	/**
+	 * Orderes {@link SimpleFeature Features} according to an attribute
+	 * (ascending).
+	 * 
+	 * @param fi
+	 *            an iterator for the features
+	 * @param attrName
+	 *            the attribute to order by
+	 * @return a list of ordered features
+	 */
+	public static Vector<SimpleFeature> sortFeatures(
+			FeatureIterator<SimpleFeature> fi, String attrName) {
+		// First create a SortedMap with CollisionList
+		SortedMap<Comparable<?>, Vector<SimpleFeature>> sortedFeatureLists = new TreeMap<Comparable<?>, Vector<SimpleFeature>>();
+		for (; fi.hasNext();) {
+			SimpleFeature f = fi.next();
+			// Check whether attribute value is Comparable
+			Object attrValue = f.getAttribute(attrName);
+			if (attrValue != null && !(attrValue instanceof Comparable))
+				throw new UnsupportedOperationException(
+						"SimpleFeature sort only supported for Comparable attributes: "
+								+ LangUtil.getSimpleClassName(attrValue));
+			// Determine X value as sort attribute (NULL not permitted for
+			// XYDateset!)
+			Comparable<?> xValue = (Comparable<?>) attrValue;
+			if (xValue == null)
+				continue;
 
-  /**
-   * Fuehrt eine Join-Operation zwischen zwei {@link FeatureCollection} durch.
-   * Hierfuer wird eine einfacher Nested-Loop-Join durchgefuehrt.
-   * In den optionalen Parametern koennen Attribut-Namen angegeben werden, die
-   * in die Ergebnis-Colletion uebernommen werden (Projektion).<br>
-   * <b>Achtung:</b> Wird diese Option verwendet, sollte sichergestellt sein,
-   * dass {@code fc1} und {@code fc2} KEINE gleichen Attributnamen hat! Ansonsten
-   * wird (aus technischen Gruenden) das Attribut von {@code fc2} uebernommen.
-   * @param fc1       erste FeatureCollection
-   * @param joinAttr1 Attribut-Name in der ersten FeatureCollection
-   * @param compareOp Operation, mit der der JOIN-Vergleich durchgefuehrt wird
-   * @param fc2       zweiten FeatureCollection
-   * @param joinAttr2 Attribut-Name in der zweiten FeatureCollection
-   * @param projAttr  Attribute (von {@code fc1} und {@code fc2}), die in das
-   *                  Ergebnis übernommen werden (Projektion)
-   * @return eine <b>neue</b> Instanz von {@link FeatureCollection}
-   * @throws SchemaException falls das Erweitern des SimpleFeature-Schemas scheitert
-   * @throws IllegalAttributeException falls das Einfuegen der Features in die
-   *         neue {@link FeatureCollection} scheitert
-   */
-  public static FeatureCollection<SimpleFeatureType, SimpleFeature> joinFeatureCollection(JoinType joinType, FeatureCollection<SimpleFeatureType, SimpleFeature> fc1, String joinAttr1, AttributeFilter compareOp, FeatureCollection<SimpleFeatureType, SimpleFeature> fc2, String joinAttr2, String... projAttr) throws SchemaException, IllegalAttributeException  {
-    // RIGHT-OUTER-JOIN reaslisiert als "inverser" LEFT-OUTER-JOIN
-    // Bemerkung: nur Uebergangsloesung, da nicht ganz sauber!!
-    //            Attribut-Reihenfolge wird vertauscht...
-    if ( joinType == JoinType.RIGHT_OUTER )
-//      throw new IllegalArgumentException("Join type RIGHT_OUTER not yet supported.");
-      return joinFeatureCollection(
-          JoinType.LEFT_OUTER,
-          fc2,
-          joinAttr2,
-          compareOp.inverse(),
-          fc1,
-          joinAttr1,
-          projAttr
-      );
+			// Check whether collision list exists
+			Vector<SimpleFeature> collList = sortedFeatureLists.get(xValue);
+			if (collList == null) {
+				collList = new Vector<SimpleFeature>();
+				sortedFeatureLists.put(xValue, collList);
+			}
+			// Add feature to collision list
+			collList.add(f);
+		}
 
-    // Flag, ob Projektion erfolgen soll
-    boolean projection = projAttr.length > 0;
+		// Put the (now ordered) features from the collision lists
+		// into an temporary list to create a list of Features
+		Vector<SimpleFeature> sortedFeatures = new Vector<SimpleFeature>();
+		for (Vector<SimpleFeature> collList : sortedFeatureLists.values())
+			for (SimpleFeature f : collList)
+				sortedFeatures.add(f);
 
-    // Schema erstellen
-    SimpleFeatureType fType1 = fc1.getSchema();
-    SimpleFeatureType fType2 = fc2.getSchema();
-    SimpleFeatureType resultType = null;
-    if ( fType1 == null )
-      throw new UnsupportedOperationException("JOIN can not be performed. FeatureCollection 1 seems to be empty.");
-    if ( fType2 == null )
-      throw new UnsupportedOperationException("JOIN can not be performed. FeatureCollection 2 seems to be empty.");
-    if ( fType1.getDescriptor(joinAttr1) == null )
-      throw new UnsupportedOperationException("JOIN can not be performed. FeatureCollection 1 does not contain the JOIN-Attribute: "+joinAttr1);
-    if ( fType2.getDescriptor(joinAttr2) == null )
-      throw new UnsupportedOperationException("JOIN can not be performed. FeatureCollection 2 does not contain the JOIN-Attribute: "+joinAttr2);
+		return sortedFeatures;
+	}
 
-    // Wenn keine Projektion, dann alle Attribute von fc1 mit denen
-    // von fc2 vereinen; sonst neuen SimpleFeatureType aufbauen
-    if ( !projection )
-        resultType = extendFeatureType(fType1, fType2.getAttributeDescriptors());
-    else {
-      // Leeren SimpleFeature-Type erzeugen
-      SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
-      builder.setName(fType1.getName());
-      // Projektions-Attribute hinzufuegen
-      for (String attrName : projAttr) {
-        // erste Wahl: Attribut von fc2 uebernehmen (da beim Belegen
-        //             von "fValues" der Attributwert aus fc1 in der inneren
-        //             FOR-Schleife ggf. durch den Attributwert von fc2
-        //             ueberschrieben wird!)
-        AttributeDescriptor aType = fType2.getDescriptor(attrName);
-        // zweite Wahl: Attribut von fc1 uebernehmen
-        if ( aType == null )
-          aType = fType1.getDescriptor(attrName);
-        // Attribut in den SimpleFeatureType einfuegen
-        if ( aType != null )
-          builder.add( aType );
-      }
-      // SimpleFeatureType erzeugen
-      resultType = builder.buildFeatureType();
-    }
+	/**
+	 * Erweitert das Schema einer {@link FeatureCollection} um eine Reihe von
+	 * Attributen.
+	 * 
+	 * @param fc
+	 *            zu erweiternde FeatureCollection
+	 * @param aTypes
+	 *            Typen der neuen Attribute
+	 * @return eine <b>neue</b> Instanz von {@link FeatureCollection}
+	 * @throws SchemaException
+	 *             falls das Erweitern des SimpleFeature-Schemas scheitert
+	 * @throws IllegalAttributeException
+	 *             falls das Einfuegen der Features in die neue
+	 *             {@link FeatureCollection} scheitert
+	 */
+	public static FeatureCollection<SimpleFeatureType, SimpleFeature> extendFeatureCollection(
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fc,
+			AttributeDescriptor... aTypes) throws SchemaException,
+			IllegalAttributeException {
+		// Schema erstellen
+		SimpleFeatureType fType = fc.getSchema();
+		SimpleFeatureType resultType = extendFeatureType(fType, aTypes);
 
-    // Neue Collection erstellen
-    DefaultFeatureCollection resultFc = (DefaultFeatureCollection)DefaultFeatureCollections.newCollection();
-    FeatureIterator<SimpleFeature> fi = fc1.features();
-    // Array fuer die Attribut-Werte eines Features
-    Object[] fValues = new Object[resultType.getAttributeCount()];
+		// Neue Collection erstellen
+		FeatureCollection<SimpleFeatureType, SimpleFeature> resultFc = DefaultFeatureCollections
+				.newCollection();
+		FeatureIterator<SimpleFeature> fi = fc.features();
+		// Array fuer die Attribut-Werte eines Features
 
-    // NestedLoopJoin: Alle Features der ersten Collection durchgehen
-    //                 und die passenden in der zweiten Collection suchen
-    AttributeFilter filter = compareOp.clone();
-    for (SimpleFeature f1 = null; fi.hasNext(); ) {
-      f1 = fi.next();
-      // Werte der 1. Features in Array schreiben
-      if ( !projection )
-        // Alle Attribut-Werte aus fc1
-        getAttributeValues(f1,fValues,0);
-      else
-        // Nur Werte der Projektions-Attribute aus fc1
-        getAttributeValues(f1,fValues,0,projAttr);
+		List<Object> fValues = new ArrayList<Object>(resultType
+				.getAttributeCount());
+		for (; fi.hasNext();) {
+			// Werte der alten Attribute in Array schreiben
+			fValues = fi.next().getAttributes();
 
-      // Passende Features in 2. Colletion suchen
-      filter.setAttributeName(joinAttr2);
-      filter.setCompareValue(f1.getAttribute(joinAttr1));
-      FeatureIterator<SimpleFeature> joinedFeatures = fc2.subCollection(filter).features();
+			// Default-Werte der neuen Attribute in Array schreiben
+			for (int i = fType.getAttributeCount(); i < fValues.size(); i++)
+				fValues.set(i, resultType.getAttributeDescriptors().get(i)
+						.getDefaultValue());
+			// Erweitertes SimpleFeature erzeugen und FeatureCollection fuellen
+			resultFc.add(createFeature(resultType, fValues));
+		}
 
-      // Wenn LEFT-OUTER-JOIN und JOIN nicht erfolgreich, ein Dummy
-      // SimpleFeature mit Default-Werten in die Collection einfuegen
-      // Sonst: JOIN-Paare "normal" bilden
-      if ( !joinedFeatures.hasNext() && joinType == JoinType.LEFT_OUTER ) {
-        if ( !projection )
-          getDefaultAttributeValues(fType2,fValues,fType1.getAttributeCount());
-        else
-          getDefaultAttributeValues(fType2,fValues,0,projAttr);
-        // Erweitertes SimpleFeature erzeugen und FeatureCollection fuellen
-        resultFc.add( createFeature(resultType,fValues ) );
-      } else {
-        for (SimpleFeature f2 = null; joinedFeatures.hasNext(); ) {
-          f2 = joinedFeatures.next();
-          // Werte der 2. Features in Array schreiben
-          if ( !projection )
-            getAttributeValues(f2,fValues,fType1.getAttributeCount());
-          else
-            getAttributeValues(f2,fValues,0,projAttr);
-          // Erweitertes SimpleFeature erzeugen und FeatureCollection fuellen
-          SimpleFeature feature = createFeature(resultType,fValues);
-          resultFc.add( feature );
-        }
-      }
-    }
+		return resultFc;
+	}
 
-    return resultFc;
-  }
+	/**
+	 * Fuehrt eine Join-Operation zwischen zwei {@link FeatureCollection} durch.
+	 * Hierfuer wird eine einfacher Nested-Loop-Join durchgefuehrt. In den
+	 * optionalen Parametern koennen Attribut-Namen angegeben werden, die in die
+	 * Ergebnis-Colletion uebernommen werden (Projektion).<br>
+	 * <b>Achtung:</b> Wird diese Option verwendet, sollte sichergestellt sein,
+	 * dass {@code fc1} und {@code fc2} KEINE gleichen Attributnamen hat!
+	 * Ansonsten wird (aus technischen Gruenden) das Attribut von {@code fc2}
+	 * uebernommen.
+	 * 
+	 * @param fc1
+	 *            erste FeatureCollection
+	 * @param joinAttr1
+	 *            Attribut-Name in der ersten FeatureCollection
+	 * @param compareOp
+	 *            Operation, mit der der JOIN-Vergleich durchgefuehrt wird
+	 * @param fc2
+	 *            zweiten FeatureCollection
+	 * @param joinAttr2
+	 *            Attribut-Name in der zweiten FeatureCollection
+	 * @param projAttr
+	 *            Attribute (von {@code fc1} und {@code fc2}), die in das
+	 *            Ergebnis übernommen werden (Projektion)
+	 * @return eine <b>neue</b> Instanz von {@link FeatureCollection}
+	 * @throws SchemaException
+	 *             falls das Erweitern des SimpleFeature-Schemas scheitert
+	 * @throws IllegalAttributeException
+	 *             falls das Einfuegen der Features in die neue
+	 *             {@link FeatureCollection} scheitert
+	 */
+	public static FeatureCollection<SimpleFeatureType, SimpleFeature> joinFeatureCollection(
+			JoinType joinType,
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fc1,
+			String joinAttr1, AttributeFilter compareOp,
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fc2,
+			String joinAttr2, String... projAttr) throws SchemaException,
+			IllegalAttributeException {
+		// RIGHT-OUTER-JOIN reaslisiert als "inverser" LEFT-OUTER-JOIN
+		// Bemerkung: nur Uebergangsloesung, da nicht ganz sauber!!
+		// Attribut-Reihenfolge wird vertauscht...
+		if (joinType == JoinType.RIGHT_OUTER)
+			// throw new
+			// IllegalArgumentException("Join type RIGHT_OUTER not yet supported.");
+			return joinFeatureCollection(JoinType.LEFT_OUTER, fc2, joinAttr2,
+					compareOp.inverse(), fc1, joinAttr1, projAttr);
 
-  /**
-   * Fuehrt eine (Full-Outer-) Join-Operation zwischen zwei {@link FeatureCollection}
-   * durch.
-   * Hierfuer wird eine einfacher Nested-Loop-Join durchgefuehrt.
-   * In den optionalen Parametern koennen Attribut-Namen angegeben werden, die
-   * in die Ergebnis-Colletion uebernommen werden (Projektion).<br>
-   * <b>Achtung:</b> Wird diese Option verwendet, sollte sichergestellt sein,
-   * dass {@code fc1} und {@code fc2} KEINE gleichen Attributnamen hat! Ansonsten
-   * wird (aus technischen Gruenden) das Attribut von {@code fc2} uebernommen.
-   * @param fc1       erste FeatureCollection
-   * @param joinAttr1 Attribut-Name in der ersten FeatureCollection
-   * @param compareOp Operation, mit der der JOIN-Vergleich durchgefuehrt wird
-   * @param fc2       zweiten FeatureCollection
-   * @param joinAttr2 Attribut-Name in der zweiten FeatureCollection
-   * @param projAttr  Attribute (von {@code fc1} und {@code fc2}), die in das
-   *                  Ergebnis übernommen werden (Projektion)
-   * @return eine <b>neue</b> Instanz von {@link FeatureCollection}
-   * @throws SchemaException falls das Erweitern des SimpleFeature-Schemas scheitert
-   * @throws IllegalAttributeException falls das Einfuegen der Features in die
-   *         neue {@link FeatureCollection} scheitert
-   */
-  public static FeatureCollection<SimpleFeatureType, SimpleFeature> joinFeatureCollection(FeatureCollection<SimpleFeatureType, SimpleFeature> fc1, String joinAttr1, AttributeFilter compareOp, FeatureCollection<SimpleFeatureType, SimpleFeature> fc2, String joinAttr2, String... projAttr) throws SchemaException, IllegalAttributeException  {
-    return joinFeatureCollection(JoinType.FULL, fc1, joinAttr1, compareOp, fc2, joinAttr2, projAttr);
-  }
+		// Flag, ob Projektion erfolgen soll
+		boolean projection = projAttr.length > 0;
 
-  /**
-   * Fuehrt eine (Full-Outer-) Equi-Join-Operation zwischen zwei
-   * {@link FeatureCollection} durch.
-   * @param fc1       erste FeatureCollection
-   * @param joinAttr1 Attribut-Name in der ersten FeatureCollection
-   * @param fc2       zweiten FeatureCollection
-   * @param joinAttr2 Attribut-Name in der zweiten FeatureCollection
-   * @param projAttr  Attribute (von {@code fc1} und {@code fc2}), die in das
-   *                  Ergebnis übernommen werden (Projektion)
-   * @return eine <b>neue</b> Instanz von {@link FeatureCollection}
-   * @throws SchemaException falls das Erweitern des SimpleFeature-Schemas scheitert
-   * @throws IllegalAttributeException falls das Einfuegen der Features in die
-   *         neue {@link FeatureCollection} scheitert
-   * @see #joinFeatureCollection(FeatureCollection, String, AttributeFilter, FeatureCollection, String)
-   * @see #AttributeFilter.EQUALS
-   */
-  public static FeatureCollection<SimpleFeatureType, SimpleFeature> joinFeatureCollection(FeatureCollection<SimpleFeatureType, SimpleFeature> fc1, String joinAttr1, FeatureCollection<SimpleFeatureType, SimpleFeature> fc2, String joinAttr2, String... projAttr) throws SchemaException, IllegalAttributeException  {
-    return joinFeatureCollection(fc1,joinAttr1,AttributeFilter.EQUALS,fc2,joinAttr2,projAttr);
-  }
+		// Schema erstellen
+		SimpleFeatureType fType1 = fc1.getSchema();
+		SimpleFeatureType fType2 = fc2.getSchema();
+		SimpleFeatureType resultType = null;
+		if (fType1 == null)
+			throw new UnsupportedOperationException(
+					"JOIN can not be performed. FeatureCollection 1 seems to be empty.");
+		if (fType2 == null)
+			throw new UnsupportedOperationException(
+					"JOIN can not be performed. FeatureCollection 2 seems to be empty.");
+		if (fType1.getDescriptor(joinAttr1) == null)
+			throw new UnsupportedOperationException(
+					"JOIN can not be performed. FeatureCollection 1 does not contain the JOIN-Attribute: "
+							+ joinAttr1);
+		if (fType2.getDescriptor(joinAttr2) == null)
+			throw new UnsupportedOperationException(
+					"JOIN can not be performed. FeatureCollection 2 does not contain the JOIN-Attribute: "
+							+ joinAttr2);
 
-  /**
-   * Liefert die Default-Werte fuer alle Attribute eines {@link SimpleFeatureType}.
-   * @param ft ein SimpleFeature-Type
-   */
-  public static Object[] getDefaultAttributeValues(SimpleFeatureType ft) {
-    return getDefaultAttributeValues(ft,null,0);
-  }
+		// Wenn keine Projektion, dann alle Attribute von fc1 mit denen
+		// von fc2 vereinen; sonst neuen SimpleFeatureType aufbauen
+		if (!projection)
+			resultType = extendFeatureType(fType1, fType2
+					.getAttributeDescriptors());
+		else {
+			// Leeren SimpleFeature-Type erzeugen
+			SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
+			builder.setName(fType1.getName());
+			// Projektions-Attribute hinzufuegen
+			for (String attrName : projAttr) {
+				// erste Wahl: Attribut von fc2 uebernehmen (da beim Belegen
+				// von "fValues" der Attributwert aus fc1 in der inneren
+				// FOR-Schleife ggf. durch den Attributwert von fc2
+				// ueberschrieben wird!)
+				AttributeDescriptor aType = fType2.getDescriptor(attrName);
+				// zweite Wahl: Attribut von fc1 uebernehmen
+				if (aType == null)
+					aType = fType1.getDescriptor(attrName);
+				// Attribut in den SimpleFeatureType einfuegen
+				if (aType != null)
+					builder.add(aType);
+			}
+			// SimpleFeatureType erzeugen
+			resultType = builder.buildFeatureType();
+		}
 
-  /**
-   * Liefert die Default-Werte fuer eine Reihen von Attributwerten
-   * eines FeatureTypes.
-   * @param ft ein SimpleFeature-Type
-   * @param destArray Array, in dem die Objekte abgelegt werden (wenn {@code null},
-   *                 wird ein neuer Array erzeugt)
-   * @param destStartIdx Start-Index in {@code destArray} ab dem die Attributwerte
-   *                     abgelegt werden
-   * @param attrName Attribute aus {@link f}
-   * @return {@code destArray} oder einen neuen Array {@code Object[destStartIdx + attrName.length]}
-   */
-  public static Object[] getDefaultAttributeValues(SimpleFeatureType ft, Object[] destArray, int destStartIdx, String... attrName) {
-    // Wenn keine Attribute angegeben sind, alle verwenden
-    int attrCount = attrName.length > 0 ? attrName.length : ft.getAttributeCount();
+		// Neue Collection erstellen
+		DefaultFeatureCollection resultFc = (DefaultFeatureCollection) DefaultFeatureCollections
+				.newCollection();
+		FeatureIterator<SimpleFeature> fi = fc1.features();
+		// Array fuer die Attribut-Werte eines Features
+		Object[] fValues = new Object[resultType.getAttributeCount()];
 
-    if ( destArray == null )
-      destArray = new Object[destStartIdx + attrCount];
-    if ( destArray.length < destStartIdx + attrCount )
-      throw new IllegalArgumentException("Destination array "+destArray.length+" with start index "+destStartIdx+" too small for "+attrName.length+" attribute values!");
+		// NestedLoopJoin: Alle Features der ersten Collection durchgehen
+		// und die passenden in der zweiten Collection suchen
+		AttributeFilter filter = compareOp.clone();
+		for (SimpleFeature f1 = null; fi.hasNext();) {
+			f1 = fi.next();
+			// Werte der 1. Features in Array schreiben
+			if (!projection)
+				// Alle Attribut-Werte aus fc1
+				getAttributeValues(f1, fValues, 0);
+			else
+				// Nur Werte der Projektions-Attribute aus fc1
+				getAttributeValues(f1, fValues, 0, projAttr);
 
-    // Wenn keine Attribute angegeben sind, alle verwenden
-    for (int i=0; i<attrCount; i++) {
-      AttributeDescriptor attrType = attrName.length > 0 ? ft.getDescriptor(attrName[i]) : ft.getDescriptor(i);
-      // wenn attrType = null, dann gibt es das Attribut im SimpleFeatureType nicht
-      // -> destArray nicht ueberschreiben
-      if ( attrType != null )
-        destArray[ destStartIdx+i ] = getDefaultAttributeValue(attrType);
-    }
-    return destArray;
-  }
+			// Passende Features in 2. Colletion suchen
+			filter.setAttributeName(joinAttr2);
+			filter.setCompareValue(f1.getAttribute(joinAttr1));
+			FeatureIterator<SimpleFeature> joinedFeatures = fc2.subCollection(
+					filter).features();
 
-  /**
-   * Liefert den Default-Wert fuer ein Attribut.
-   * @param attrType Attribut-Typ
-   * @return {@code null}, wenn das Attribut NILLABLE ist
-   */
-  public static Object getDefaultAttributeValue(AttributeDescriptor attrType) {
-    return( getDefaultAttributeValue(attrType, true) );
-  }
+			// Wenn LEFT-OUTER-JOIN und JOIN nicht erfolgreich, ein Dummy
+			// SimpleFeature mit Default-Werten in die Collection einfuegen
+			// Sonst: JOIN-Paare "normal" bilden
+			if (!joinedFeatures.hasNext() && joinType == JoinType.LEFT_OUTER) {
+				if (!projection)
+					getDefaultAttributeValues(fType2, fValues, fType1
+							.getAttributeCount());
+				else
+					getDefaultAttributeValues(fType2, fValues, 0, projAttr);
+				// Erweitertes SimpleFeature erzeugen und FeatureCollection
+				// fuellen
+				resultFc.add(createFeature(resultType, fValues));
+			} else {
+				for (SimpleFeature f2 = null; joinedFeatures.hasNext();) {
+					f2 = joinedFeatures.next();
+					// Werte der 2. Features in Array schreiben
+					if (!projection)
+						getAttributeValues(f2, fValues, fType1
+								.getAttributeCount());
+					else
+						getAttributeValues(f2, fValues, 0, projAttr);
+					// Erweitertes SimpleFeature erzeugen und FeatureCollection
+					// fuellen
+					SimpleFeature feature = createFeature(resultType, fValues);
+					resultFc.add(feature);
+				}
+			}
+		}
 
-  /**
-   * Liefert den Default-Wert fuer ein Attribut.
-   * @param attrType Attribut-Typ
-   * @param allowNull wenn {@code false}, wird in jedem Fall ein Wert ungleich
-   *                  {@code null} geliefert, auch wenn das Attribut NILLABLE ist
-   */
-  public static Object getDefaultAttributeValue(AttributeDescriptor attrType, boolean allowNull) {
-//    AutoValueGenerator avg = getAutoValueGenerator(attrType);
-//    Object attrValue = (avg == null) ? attrType.createDefaultValue() : avg.getNextValue();
-    Object attrValue = attrType.getDefaultValue();
-    if ( attrValue == null && ( !attrType.isNillable() || !allowNull ) ) {
-      attrValue = getDefaultAttributeValue( attrType.getType().getBinding() );
-      if ( attrValue == null )
-        LOGGER.warn("Could not create default value for not-null attribute '"+attrType.getLocalName()+"': "+attrType.getType().getBinding().getSimpleName());
-    }
-    return attrValue;
-  }
+		return resultFc;
+	}
 
-  /**
-   * Liefert den Default-Wert fuer ein Attribut.
-   * @param attrType Attribut-Typ
-   * @return {@code null}, falls {@link DataUtilities#defaultValue(Class)} keinen
-   *         Defaul-Wert ermitteln kann (anstelle einer Exception!)
-   */
-  public static Object getDefaultAttributeValue(Class attrType) {
-    Object attrValue = null;
-    try {
-      // DataUtilities.defaultValue(.) kann BigDecimal und BigInteger
-      // nicht verarbeiten (gibt null zurueck!)
-      if ( BigDecimal.class.isAssignableFrom( attrType ) )
-        return new BigDecimal(0.0);
-      if ( BigInteger.class.isAssignableFrom( attrType ) )
-        return new BigInteger("0");
-      attrValue = DataUtilities.defaultValue(attrType);
-    } catch (IllegalArgumentException err) {
-      // no default value could be generated for this type
-      // --> ignore that
-    }
-    return attrValue;
-  }
+	/**
+	 * Fuehrt eine (Full-Outer-) Join-Operation zwischen zwei
+	 * {@link FeatureCollection} durch. Hierfuer wird eine einfacher
+	 * Nested-Loop-Join durchgefuehrt. In den optionalen Parametern koennen
+	 * Attribut-Namen angegeben werden, die in die Ergebnis-Colletion
+	 * uebernommen werden (Projektion).<br>
+	 * <b>Achtung:</b> Wird diese Option verwendet, sollte sichergestellt sein,
+	 * dass {@code fc1} und {@code fc2} KEINE gleichen Attributnamen hat!
+	 * Ansonsten wird (aus technischen Gruenden) das Attribut von {@code fc2}
+	 * uebernommen.
+	 * 
+	 * @param fc1
+	 *            erste FeatureCollection
+	 * @param joinAttr1
+	 *            Attribut-Name in der ersten FeatureCollection
+	 * @param compareOp
+	 *            Operation, mit der der JOIN-Vergleich durchgefuehrt wird
+	 * @param fc2
+	 *            zweiten FeatureCollection
+	 * @param joinAttr2
+	 *            Attribut-Name in der zweiten FeatureCollection
+	 * @param projAttr
+	 *            Attribute (von {@code fc1} und {@code fc2}), die in das
+	 *            Ergebnis übernommen werden (Projektion)
+	 * @return eine <b>neue</b> Instanz von {@link FeatureCollection}
+	 * @throws SchemaException
+	 *             falls das Erweitern des SimpleFeature-Schemas scheitert
+	 * @throws IllegalAttributeException
+	 *             falls das Einfuegen der Features in die neue
+	 *             {@link FeatureCollection} scheitert
+	 */
+	public static FeatureCollection<SimpleFeatureType, SimpleFeature> joinFeatureCollection(
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fc1,
+			String joinAttr1, AttributeFilter compareOp,
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fc2,
+			String joinAttr2, String... projAttr) throws SchemaException,
+			IllegalAttributeException {
+		return joinFeatureCollection(JoinType.FULL, fc1, joinAttr1, compareOp,
+				fc2, joinAttr2, projAttr);
+	}
 
-  /**
-   * Liefert eine Reihen von Attributwerten eines Features.
-   * @param f ein SimpleFeature
-   * @param destArray Array, in dem die Objekte abgelegt werden (wenn {@code null},
-   *                 wird ein neuer Array erzeugt)
-   * @param destStartIdx Start-Index in {@code destArray} ab dem die Attributwerte
-   *                     abgelegt werden
-   * @param attrName Attribute des Features, deren Werte geliefert werden (wenn
-   *                 {@code null} werden alle Attribute geliefert)
-   * @return {@code destArray} oder einen neuen Array {@code Object[destStartIdx + attrName.length]}
-   */
-  public static Object[] getAttributeValues(SimpleFeature f, Object[] destArray, int destStartIdx, String... attrName) {
-    if ( destArray == null )
-      destArray = new Object[destStartIdx + attrName.length];
-    if ( destArray.length < destStartIdx + attrName.length )
-      throw new IllegalArgumentException("Destination array "+destArray.length+" with start index "+destStartIdx+" too small for "+attrName.length+" attribute values!");
+	/**
+	 * Fuehrt eine (Full-Outer-) Equi-Join-Operation zwischen zwei
+	 * {@link FeatureCollection} durch.
+	 * 
+	 * @param fc1
+	 *            erste FeatureCollection
+	 * @param joinAttr1
+	 *            Attribut-Name in der ersten FeatureCollection
+	 * @param fc2
+	 *            zweiten FeatureCollection
+	 * @param joinAttr2
+	 *            Attribut-Name in der zweiten FeatureCollection
+	 * @param projAttr
+	 *            Attribute (von {@code fc1} und {@code fc2}), die in das
+	 *            Ergebnis übernommen werden (Projektion)
+	 * @return eine <b>neue</b> Instanz von {@link FeatureCollection}
+	 * @throws SchemaException
+	 *             falls das Erweitern des SimpleFeature-Schemas scheitert
+	 * @throws IllegalAttributeException
+	 *             falls das Einfuegen der Features in die neue
+	 *             {@link FeatureCollection} scheitert
+	 * @see #joinFeatureCollection(FeatureCollection, String, AttributeFilter,
+	 *      FeatureCollection, String)
+	 * @see #AttributeFilter
+	 */
+	public static FeatureCollection<SimpleFeatureType, SimpleFeature> joinFeatureCollection(
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fc1,
+			String joinAttr1,
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fc2,
+			String joinAttr2, String... projAttr) throws SchemaException,
+			IllegalAttributeException {
+		return joinFeatureCollection(fc1, joinAttr1, AttributeFilter.EQUALS,
+				fc2, joinAttr2, projAttr);
+	}
 
-    // Wenn keine Attribute angegeben sind, alle verwenden
-    int attrCount = attrName.length > 0 ? attrName.length : f.getAttributeCount();
-    for (int i=0; i<attrCount; i++) {
-      Object attr = attrName.length > 0 ? f.getAttribute(attrName[i]) : f.getAttribute(i);
-      // wenn attr = null, dann gibt es das Attribut im SimpleFeature nicht
-      // -> destArray nicht ueberschreiben
-      if ( attr != null )
-        destArray[ destStartIdx+i ] = attr;
-    }
-    return destArray;
-  }
+	/**
+	 * Liefert die Default-Werte fuer alle Attribute eines
+	 * {@link SimpleFeatureType}.
+	 * 
+	 * @param ft
+	 *            ein SimpleFeature-Type
+	 */
+	public static Object[] getDefaultAttributeValues(SimpleFeatureType ft) {
+		return getDefaultAttributeValues(ft, null, 0);
+	}
 
-  /**
-   * Liefert eine Reihen von Attributwerten eines Features.
-   * @param f ein SimpleFeature
-   * @param attrName Attribute des Features, deren Werte geliefert werden (wenn
-   *                 {@code null} werden alle Attribute geliefert)
-   * @return neuer Array {@code Object[attrName.length]}
-   */
-  public static Object[] getAttributeValues(SimpleFeature f, String... attrName) {
-    return getAttributeValues(f,null,0,attrName);
-  }
+	/**
+	 * Liefert die Default-Werte fuer eine Reihen von Attributwerten eines
+	 * FeatureTypes.
+	 * 
+	 * @param ft
+	 *            ein SimpleFeature-Type
+	 * @param destArray
+	 *            Array, in dem die Objekte abgelegt werden (wenn {@code null},
+	 *            wird ein neuer Array erzeugt)
+	 * @param destStartIdx
+	 *            Start-Index in {@code destArray} ab dem die Attributwerte
+	 *            abgelegt werden
+	 * @param attrName
+	 *            Attribute aus {@link f}
+	 * @return {@code destArray} oder einen neuen Array {@code
+	 *         Object[destStartIdx + attrName.length]}
+	 */
+	public static Object[] getDefaultAttributeValues(SimpleFeatureType ft,
+			Object[] destArray, int destStartIdx, String... attrName) {
+		// Wenn keine Attribute angegeben sind, alle verwenden
+		int attrCount = attrName.length > 0 ? attrName.length : ft
+				.getAttributeCount();
 
-  /**
-   * Liefert eine Reihen von Attributwerten eines Features.
-   * @param f ein SimpleFeature
-   * @param destMap Map, in dem die Objekte abgelegt werden (wenn {@code null},
-   *                 wird eine neue {@link HashMap} erzeugt)
-   * @param attrName Attribute des Features, deren Werte geliefert werden (wenn
-   *                 {@code null} werden alle Attribute geliefert)
-   * @return {@code destArray} oder einen neuen Array {@code Object[destStartIdx + attrName.length]}
-   */
-  public static Map<String,Object> getAttributeValues(SimpleFeature f, Map<String,Object> destMap, String... attrName) {
-    if ( destMap == null )
-      destMap = new HashMap<String,Object>();
+		if (destArray == null)
+			destArray = new Object[destStartIdx + attrCount];
+		if (destArray.length < destStartIdx + attrCount)
+			throw new IllegalArgumentException("Destination array "
+					+ destArray.length + " with start index " + destStartIdx
+					+ " too small for " + attrName.length
+					+ " attribute values!");
 
-    if ( attrName.length > 0 )
-      for (int i=0; i<attrName.length; i++)
-        destMap.put( attrName[i], f.getAttribute(attrName[i]) );
-    else
-      for (int i=0; i<f.getAttributeCount(); i++)
-        destMap.put( f.getFeatureType().getName().getLocalPart(), f.getAttribute(i) );
+		// Wenn keine Attribute angegeben sind, alle verwenden
+		for (int i = 0; i < attrCount; i++) {
+			AttributeDescriptor attrType = attrName.length > 0 ? ft
+					.getDescriptor(attrName[i]) : ft.getDescriptor(i);
+			// wenn attrType = null, dann gibt es das Attribut im
+			// SimpleFeatureType nicht
+			// -> destArray nicht ueberschreiben
+			if (attrType != null)
+				destArray[destStartIdx + i] = getDefaultAttributeValue(attrType);
+		}
+		return destArray;
+	}
 
-    return destMap;
-  }
-  
-  /**
-   * Fuehrt eine Join-Operation zwischen einer {@link FeatureCollection} und
-   * einem {@link ResultSet} durch, in dem Zusatz-Informationen hinterlegt.
-   * Hierzu wird das ResultSet zunaecht in eine {@link FeatureCollection}
-   * umgewandelt und anschliessend ein Left-Outer-EquiJoin zwischen
-   * den beiden Collections ausgewertet.
-   * @param fc          eine FeatureCollection
-   * @param fcJoinAttr  JOIN-Attribut in der FeatureCollection
-   * @param rs          ResultSet mit Zusatz-Informationen
-   * @param rsJoinAttr  JOIN-Attribut im ResultSet
-   * @return eine <b>neue</b> Instanz von {@link FeatureCollection}
-   * @throws SchemaException falls das Erweitern des SimpleFeature-Schemas scheitert
-   * @throws IllegalAttributeException falls das Einfuegen der Features in die
-   *         neue {@link FeatureCollection} scheitert
-   */
-  public static FeatureCollection<SimpleFeatureType, SimpleFeature> joinFeatureCollection(FeatureCollection<SimpleFeatureType, SimpleFeature> fc, String fcJoinAttr, ResultSet rs, String rsJoinAttr, String... projAttr) throws SchemaException, IllegalAttributeException, SQLException  {
-    return joinFeatureCollection(fc, fcJoinAttr, AttributeFilter.EQUALS, rs, rsJoinAttr);
-  }
+	/**
+	 * Liefert den Default-Wert fuer ein Attribut.
+	 * 
+	 * @param attrType
+	 *            Attribut-Typ
+	 * @return {@code null}, wenn das Attribut NILLABLE ist
+	 */
+	public static Object getDefaultAttributeValue(AttributeDescriptor attrType) {
+		return (getDefaultAttributeValue(attrType, true));
+	}
 
-  /**
-   * Fuehrt eine Join-Operation zwischen einer {@link FeatureCollection} und
-   * einem {@link ResultSet} durch, in dem Zusatz-Informationen hinterlegt.
-   * Hierzu wird das ResultSet zunaecht in eine {@link FeatureCollection}
-   * umgewandelt und anschliessend ein Left-Outer-Join zwischen
-   * den beiden Collections ausgewertet.
-   * @param fc          eine FeatureCollection
-   * @param fcJoinAttr  JOIN-Attribut in der FeatureCollection
-   * @param compareOp   Operation, mit der der JOIN-Vergleich durchgefuehrt wird
-   * @param rs          ResultSet mit Zusatz-Informationen
-   * @param rsJoinAttr  JOIN-Attribut im ResultSet
-   * @return eine <b>neue</b> Instanz von {@link FeatureCollection}
-   * @throws SchemaException falls das Erweitern des SimpleFeature-Schemas scheitert
-   * @throws IllegalAttributeException falls das Einfuegen der Features in die
-   *         neue {@link FeatureCollection} scheitert
-   */
-  public static FeatureCollection<SimpleFeatureType, SimpleFeature> joinFeatureCollection(FeatureCollection<SimpleFeatureType, SimpleFeature> fc, String fcJoinAttr, AttributeFilter compareOp, ResultSet rs, String rsJoinAttr, String... projAttr) throws SchemaException, IllegalAttributeException, SQLException  {
-    return joinFeatureCollection(JoinType.LEFT_OUTER, fc, fcJoinAttr, compareOp, rs, rsJoinAttr, projAttr);
+	/**
+	 * Liefert den Default-Wert fuer ein Attribut.
+	 * 
+	 * @param attrType
+	 *            Attribut-Typ
+	 * @param allowNull
+	 *            wenn {@code false}, wird in jedem Fall ein Wert ungleich
+	 *            {@code null} geliefert, auch wenn das Attribut NILLABLE ist
+	 */
+	public static Object getDefaultAttributeValue(AttributeDescriptor attrType,
+			boolean allowNull) {
+		// AutoValueGenerator avg = getAutoValueGenerator(attrType);
+		// Object attrValue = (avg == null) ? attrType.createDefaultValue() :
+		// avg.getNextValue();
+		Object attrValue = attrType.getDefaultValue();
+		if (attrValue == null && (!attrType.isNillable() || !allowNull)) {
+			attrValue = getDefaultAttributeValue(attrType.getType()
+					.getBinding());
+			if (attrValue == null)
+				LOGGER
+						.warn("Could not create default value for not-null attribute '"
+								+ attrType.getLocalName()
+								+ "': "
+								+ attrType.getType().getBinding()
+										.getSimpleName());
+		}
+		return attrValue;
+	}
 
-  }
+	/**
+	 * Liefert den Default-Wert fuer ein Attribut.
+	 * 
+	 * @param attrType
+	 *            Attribut-Typ
+	 * @return {@code null}, falls {@link DataUtilities#defaultValue(Class)}
+	 *         keinen Defaul-Wert ermitteln kann (anstelle einer Exception!)
+	 */
+	public static Object getDefaultAttributeValue(Class attrType) {
+		Object attrValue = null;
+		try {
+			// DataUtilities.defaultValue(.) kann BigDecimal und BigInteger
+			// nicht verarbeiten (gibt null zurueck!)
+			if (BigDecimal.class.isAssignableFrom(attrType))
+				return new BigDecimal(0.0);
+			if (BigInteger.class.isAssignableFrom(attrType))
+				return new BigInteger("0");
+			attrValue = DataUtilities.defaultValue(attrType);
+		} catch (IllegalArgumentException err) {
+			// no default value could be generated for this type
+			// --> ignore that
+		}
+		return attrValue;
+	}
 
-  /**
-   * Fuehrt eine Join-Operation zwischen einer {@link FeatureCollection} und
-   * einem {@link ResultSet} durch, in dem Zusatz-Informationen hinterlegt.
-   * Hierzu wird das ResultSet zunaecht in eine {@link FeatureCollection}
-   * umgewandelt und anschliessend ein Join zwischen
-   * den beiden Collections ausgewertet.
-   * @param joinType    Join-Typ
-   * @param fc          eine FeatureCollection
-   * @param fcJoinAttr  JOIN-Attribut in der FeatureCollection
-   * @param compareOp   Operation, mit der der JOIN-Vergleich durchgefuehrt wird
-   * @param rs          ResultSet mit Zusatz-Informationen
-   * @param rsJoinAttr  JOIN-Attribut im ResultSet
-   * @return eine <b>neue</b> Instanz von {@link FeatureCollection}
-   * @throws SchemaException falls das Erweitern des SimpleFeature-Schemas scheitert
-   * @throws IllegalAttributeException falls das Einfuegen der Features in die
-   *         neue {@link FeatureCollection} scheitert
-   */
-  public static FeatureCollection<SimpleFeatureType, SimpleFeature> joinFeatureCollection(JoinType joinType, FeatureCollection<SimpleFeatureType, SimpleFeature> fc, String fcJoinAttr, AttributeFilter compareOp, ResultSet rs, String rsJoinAttr, String... projAttr) throws SchemaException, IllegalAttributeException, SQLException  {
-    if ( fcJoinAttr == null || fcJoinAttr.trim().equals("") ) {
-      // Erste Nicht-Geometrie-Spalte suchen
-      for (AttributeDescriptor aType : fc.getSchema().getAttributeDescriptors()) {
-        if ( aType != fc.getSchema().getGeometryDescriptor() ) {
-          fcJoinAttr = aType.getName().getLocalPart();
-          break;
-        }
-      }
-      LOGGER.warn("Join-Attribut for FeatureCollection not set. First attribute used: "+fcJoinAttr);
-    }
-    if ( rsJoinAttr == null || rsJoinAttr.trim().equals("") ) {
-      rsJoinAttr = rs.getMetaData().getColumnName(1);
-      LOGGER.warn("Join-Attribut for ResultSet not set. First column used: "+rsJoinAttr);
-    }
+	/**
+	 * Liefert eine Reihen von Attributwerten eines Features.
+	 * 
+	 * @param f
+	 *            ein SimpleFeature
+	 * @param destArray
+	 *            Array, in dem die Objekte abgelegt werden (wenn {@code null},
+	 *            wird ein neuer Array erzeugt)
+	 * @param destStartIdx
+	 *            Start-Index in {@code destArray} ab dem die Attributwerte
+	 *            abgelegt werden
+	 * @param attrName
+	 *            Attribute des Features, deren Werte geliefert werden (wenn
+	 *            {@code null} werden alle Attribute geliefert)
+	 * @return {@code destArray} oder einen neuen Array {@code
+	 *         Object[destStartIdx + attrName.length]}
+	 */
+	public static Object[] getAttributeValues(SimpleFeature f,
+			Object[] destArray, int destStartIdx, String... attrName) {
+		if (destArray == null)
+			destArray = new Object[destStartIdx + attrName.length];
+		if (destArray.length < destStartIdx + attrName.length)
+			throw new IllegalArgumentException("Destination array "
+					+ destArray.length + " with start index " + destStartIdx
+					+ " too small for " + attrName.length
+					+ " attribute values!");
 
-    // FeatureCollection aus ResultSet erzeugen
-    FeatureCollection<SimpleFeatureType, SimpleFeature> rsFeatureCollection = createFeatureCollection(
-        rs,
-        // fuer den JOIN muss das Join-Attribut vorhanden sein!
-        projAttr.length > 0 ? LangUtil.extendArray(projAttr,rsJoinAttr) : projAttr
-    );
+		// Wenn keine Attribute angegeben sind, alle verwenden
+		int attrCount = attrName.length > 0 ? attrName.length : f
+				.getAttributeCount();
+		for (int i = 0; i < attrCount; i++) {
+			Object attr = attrName.length > 0 ? f.getAttribute(attrName[i]) : f
+					.getAttribute(i);
+			// wenn attr = null, dann gibt es das Attribut im SimpleFeature
+			// nicht
+			// -> destArray nicht ueberschreiben
+			if (attr != null)
+				destArray[destStartIdx + i] = attr;
+		}
+		return destArray;
+	}
 
-    // JOIN durchfuehren
-    return joinFeatureCollection(
-        joinType,              // Join-Typ
-        fc,                    // FeatureCollection
-        fcJoinAttr,            // Join-Attr. in FeatureCollection
-        compareOp,             // Join-Operator
-        rsFeatureCollection,   // ResultSet als FeatureCollection
-        rsJoinAttr,            // Join-Attr. in ResultSet
-        projAttr               // Projektions-Attribute
-    );
-  }
+	/**
+	 * Liefert eine Reihen von Attributwerten eines Features.
+	 * 
+	 * @param f
+	 *            ein SimpleFeature
+	 * @param attrName
+	 *            Attribute des Features, deren Werte geliefert werden (wenn
+	 *            {@code null} werden alle Attribute geliefert)
+	 * @return neuer Array {@code Object[attrName.length]}
+	 */
+	public static Object[] getAttributeValues(SimpleFeature f,
+			String... attrName) {
+		return getAttributeValues(f, null, 0, attrName);
+	}
 
+	/**
+	 * Liefert eine Reihen von Attributwerten eines Features.
+	 * 
+	 * @param f
+	 *            ein SimpleFeature
+	 * @param destMap
+	 *            Map, in dem die Objekte abgelegt werden (wenn {@code null},
+	 *            wird eine neue {@link HashMap} erzeugt)
+	 * @param attrName
+	 *            Attribute des Features, deren Werte geliefert werden (wenn
+	 *            {@code null} werden alle Attribute geliefert)
+	 * @return {@code destArray} oder einen neuen Array {@code
+	 *         Object[destStartIdx + attrName.length]}
+	 */
+	public static Map<String, Object> getAttributeValues(SimpleFeature f,
+			Map<String, Object> destMap, String... attrName) {
+		if (destMap == null)
+			destMap = new HashMap<String, Object>();
 
-  /**
-   * Erzeugt eine {@link FeatureCollection} aus einem {@linkplain ResultSet SQL-Result}.
-   * @param  rs        SQL-Result
-   * @param  projAttr  nur diese Attribute des ResultSet werden in die FeatureCollection
-   *                   uebernommen (wenn nicht angegeben, werden ALLE Attribute
-   *                   uebernommen)
-   * @throws SQLException falls der Zugriff auf die SQL-Metadaten scheitert
-   * @throws SchemaException falls das Erzeugen des SimpleFeatureType scheitert
-   * @throws IllegalAttributeException falls das Erzeugen eines Features scheitert
-   */
-  public static FeatureCollection<SimpleFeatureType, SimpleFeature> createFeatureCollection(ResultSet rs, String... projAttr) throws SchemaException, IllegalAttributeException, SQLException {
-    // Schema der FeatureCollection erzeugen
-    SimpleFeatureType rsFeatureType = createFeatureType(rs.getMetaData(),projAttr);
+		if (attrName.length > 0)
+			for (int i = 0; i < attrName.length; i++)
+				destMap.put(attrName[i], f.getAttribute(attrName[i]));
+		else
+			for (int i = 0; i < f.getAttributeCount(); i++)
+				destMap.put(f.getFeatureType().getName().getLocalPart(), f
+						.getAttribute(i));
 
-    // Array fuer die Attribut-Werte eines Features
-    Object[] rsFeatureValues = new Object[rsFeatureType.getAttributeCount()];
+		return destMap;
+	}
 
-    // ResultSet in FeatureCollection uebertragen
-    FeatureCollection<SimpleFeatureType, SimpleFeature> rsFeatureCollection = DefaultFeatureCollections.newCollection();
-    for ( ;rs.next(); ) {
-      for (int i=0; i<rsFeatureType.getAttributeCount(); i++)
-        rsFeatureValues[i] = rs.getObject( rsFeatureType.getDescriptor(i).getName().getLocalPart() );
-      rsFeatureCollection.add( createFeature(
-          rsFeatureType,
-          rsFeatureValues
-      ));
-    }
+	/**
+	 * Fuehrt eine Join-Operation zwischen einer {@link FeatureCollection} und
+	 * einem {@link ResultSet} durch, in dem Zusatz-Informationen hinterlegt.
+	 * Hierzu wird das ResultSet zunaecht in eine {@link FeatureCollection}
+	 * umgewandelt und anschliessend ein Left-Outer-EquiJoin zwischen den beiden
+	 * Collections ausgewertet.
+	 * 
+	 * @param fc
+	 *            eine FeatureCollection
+	 * @param fcJoinAttr
+	 *            JOIN-Attribut in der FeatureCollection
+	 * @param rs
+	 *            ResultSet mit Zusatz-Informationen
+	 * @param rsJoinAttr
+	 *            JOIN-Attribut im ResultSet
+	 * @return eine <b>neue</b> Instanz von {@link FeatureCollection}
+	 * @throws SchemaException
+	 *             falls das Erweitern des SimpleFeature-Schemas scheitert
+	 * @throws IllegalAttributeException
+	 *             falls das Einfuegen der Features in die neue
+	 *             {@link FeatureCollection} scheitert
+	 */
+	public static FeatureCollection<SimpleFeatureType, SimpleFeature> joinFeatureCollection(
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fc,
+			String fcJoinAttr, ResultSet rs, String rsJoinAttr,
+			String... projAttr) throws SchemaException,
+			IllegalAttributeException, SQLException {
+		return joinFeatureCollection(fc, fcJoinAttr, AttributeFilter.EQUALS,
+				rs, rsJoinAttr);
+	}
 
-    return rsFeatureCollection;
-  }
+	/**
+	 * Fuehrt eine Join-Operation zwischen einer {@link FeatureCollection} und
+	 * einem {@link ResultSet} durch, in dem Zusatz-Informationen hinterlegt.
+	 * Hierzu wird das ResultSet zunaecht in eine {@link FeatureCollection}
+	 * umgewandelt und anschliessend ein Left-Outer-Join zwischen den beiden
+	 * Collections ausgewertet.
+	 * 
+	 * @param fc
+	 *            eine FeatureCollection
+	 * @param fcJoinAttr
+	 *            JOIN-Attribut in der FeatureCollection
+	 * @param compareOp
+	 *            Operation, mit der der JOIN-Vergleich durchgefuehrt wird
+	 * @param rs
+	 *            ResultSet mit Zusatz-Informationen
+	 * @param rsJoinAttr
+	 *            JOIN-Attribut im ResultSet
+	 * @return eine <b>neue</b> Instanz von {@link FeatureCollection}
+	 * @throws SchemaException
+	 *             falls das Erweitern des SimpleFeature-Schemas scheitert
+	 * @throws IllegalAttributeException
+	 *             falls das Einfuegen der Features in die neue
+	 *             {@link FeatureCollection} scheitert
+	 */
+	public static FeatureCollection<SimpleFeatureType, SimpleFeature> joinFeatureCollection(
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fc,
+			String fcJoinAttr, AttributeFilter compareOp, ResultSet rs,
+			String rsJoinAttr, String... projAttr) throws SchemaException,
+			IllegalAttributeException, SQLException {
+		return joinFeatureCollection(JoinType.LEFT_OUTER, fc, fcJoinAttr,
+				compareOp, rs, rsJoinAttr, projAttr);
 
-  /**
-   * Erzeugt einen {@link SimpleFeatureType} aus einem {@linkplain ResultSetMetaData SQL-Result}.
-   * @param  metaData         SQL-Metadaten des {@link ResultSet}
-   * @param  projAttr         nur diese Attribute des ResultSet werden in den SimpleFeatureType
-   *                          uebernommen (wenn nicht angegeben, werden ALLE
-   *                          Attribute uebernommen)
-   * @throws SQLException falls der Zugriff auf die SQL-Metadaten scheitert
-   * @throws SchemaException falls das Erzeugen des SimpleFeatureType scheitert
-   */
-  public static SimpleFeatureType createFeatureType(ResultSetMetaData metaData, String... projAttr) throws SQLException, SchemaException {
-    try {
-      return createFeatureType(metaData, null, Object.class, projAttr);
-    } catch (ClassNotFoundException err) {
-      // KANN NICHT VORKOMMEN, da Object.class als Standard-Klasse angegeben
-      // ist. Exception wird nur abgefangen, damit sie nicht in throw-clause
-      // deklariert (und in uebergeordneter Methode) abgefangen werden muss
-      return null;
-    }
-  }
+	}
 
-  /**
-   * Erzeugt einen {@link SimpleFeatureType} aus einem {@linkplain ResultSet SQL-Result}.
-   * @param  metaData         SQL-Metadaten des {@link ResultSet}
-   * @param  featureTypeName  Name fuer den SimpleFeatureType (kann {@code null} sein)
-   * @param  defaultAttrClass Klasse, die verwendet als Attribut-Typ wird, wenn
-   *                          die entsprechende Klasse des ResultSet nicht zur
-   *                          Verfuegung steht (wenn {@code null}, wird eine
-   *                          Exception geworfen)
-   * @param  projAttr         nur diese Attribute des ResultSet werden in den SimpleFeatureType
-   *                          uebernommen (wenn nicht angegeben, werden ALLE
-   *                          Attribute uebernommen)
-   * @throws SQLException falls der Zugriff auf die SQL-Metadaten scheitert
-   * @throws SchemaException falls das Erzeugen des SimpleFeatureType scheitert
-   * @throws ClassNotFoundException falls eine Attribut-Klasse aus dem ResultSet
-   *         nicht erzeugt werden kann und keine Default-Klasse angegeben ist
-   */
-  public static SimpleFeatureType createFeatureType(ResultSetMetaData metaData, String featureTypeName, Class defaultAttrClass, String... projAttr) throws SQLException, SchemaException, ClassNotFoundException  {
-    if ( featureTypeName == null )
-      featureTypeName = "ResultSetFeatureType";
+	/**
+	 * Fuehrt eine Join-Operation zwischen einer {@link FeatureCollection} und
+	 * einem {@link ResultSet} durch, in dem Zusatz-Informationen hinterlegt.
+	 * Hierzu wird das ResultSet zunaecht in eine {@link FeatureCollection}
+	 * umgewandelt und anschliessend ein Join zwischen den beiden Collections
+	 * ausgewertet.
+	 * 
+	 * @param joinType
+	 *            Join-Typ
+	 * @param fc
+	 *            eine FeatureCollection
+	 * @param fcJoinAttr
+	 *            JOIN-Attribut in der FeatureCollection
+	 * @param compareOp
+	 *            Operation, mit der der JOIN-Vergleich durchgefuehrt wird
+	 * @param rs
+	 *            ResultSet mit Zusatz-Informationen
+	 * @param rsJoinAttr
+	 *            JOIN-Attribut im ResultSet
+	 * @return eine <b>neue</b> Instanz von {@link FeatureCollection}
+	 * @throws SchemaException
+	 *             falls das Erweitern des SimpleFeature-Schemas scheitert
+	 * @throws IllegalAttributeException
+	 *             falls das Einfuegen der Features in die neue
+	 *             {@link FeatureCollection} scheitert
+	 */
+	public static FeatureCollection<SimpleFeatureType, SimpleFeature> joinFeatureCollection(
+			JoinType joinType,
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fc,
+			String fcJoinAttr, AttributeFilter compareOp, ResultSet rs,
+			String rsJoinAttr, String... projAttr) throws SchemaException,
+			IllegalAttributeException, SQLException {
+		if (fcJoinAttr == null || fcJoinAttr.trim().equals("")) {
+			// Erste Nicht-Geometrie-Spalte suchen
+			for (AttributeDescriptor aType : fc.getSchema()
+					.getAttributeDescriptors()) {
+				if (aType != fc.getSchema().getGeometryDescriptor()) {
+					fcJoinAttr = aType.getName().getLocalPart();
+					break;
+				}
+			}
+			LOGGER
+					.warn("Join-Attribut for FeatureCollection not set. First attribute used: "
+							+ fcJoinAttr);
+		}
+		if (rsJoinAttr == null || rsJoinAttr.trim().equals("")) {
+			rsJoinAttr = rs.getMetaData().getColumnName(1);
+			LOGGER
+					.warn("Join-Attribut for ResultSet not set. First column used: "
+							+ rsJoinAttr);
+		}
 
-    // Projektions-Attribute in ArrayList uebertragen
-    Set<String> projAttrList = new HashSet<String>();
-    for (String attrName : projAttr)
-      projAttrList.add(attrName);
+		// FeatureCollection aus ResultSet erzeugen
+		FeatureCollection<SimpleFeatureType, SimpleFeature> rsFeatureCollection = createFeatureCollection(
+				rs,
+				// fuer den JOIN muss das Join-Attribut vorhanden sein!
+				projAttr.length > 0 ? LangUtil
+						.extendArray(projAttr, rsJoinAttr) : projAttr);
 
-    // Fuer alle Attribute aus Metadaten einen AttributeDescriptor erzeugen
-    // und diesen in SimpleFeatureType uebernehmen
-    SimpleFeatureTypeBuilder   featureTypeFac = new SimpleFeatureTypeBuilder();
-    featureTypeFac.setName(featureTypeName);
-    for (int i=1; i<=metaData.getColumnCount(); i++) {
-      String columnName = metaData.getColumnName(i);
-      // Attribut nur uebernehmen, wenn als Projektions-Attribut angegeben
-      if ( projAttr.length > 0 && !projAttrList.contains(columnName) )
-        continue;
+		// JOIN durchfuehren
+		return joinFeatureCollection(joinType, // Join-Typ
+				fc, // FeatureCollection
+				fcJoinAttr, // Join-Attr. in FeatureCollection
+				compareOp, // Join-Operator
+				rsFeatureCollection, // ResultSet als FeatureCollection
+				rsJoinAttr, // Join-Attr. in ResultSet
+				projAttr // Projektions-Attribute
+		);
+	}
 
-      Class columnClass = defaultAttrClass;
-      try {
-        columnClass = Class.forName( metaData.getColumnClassName(i) );
-      } catch (ClassNotFoundException err) {
-        if ( defaultAttrClass == null )
-          throw err;
-        // Fehler Ignorieren und Object als Attribut-Klasse verwenden
-        LOGGER.warn("Column '"+columnName+"' ("+i+"): Class '"+metaData.getColumnClassName(i)+ "' not found. '"+columnClass.getName()+"' used.");
-      }
-      boolean nillable     = metaData.isNullable(i) != ResultSetMetaData.columnNoNulls;
-      Object  defaultValue = getDefaultAttributeValue(columnClass);
-      if ( defaultValue == null && !nillable)
-        LOGGER.warn("Could not create default value for not-null attribute '"+columnName+"': "+columnClass.getSimpleName());
+	/**
+	 * Erzeugt eine {@link FeatureCollection} aus einem {@linkplain ResultSet
+	 * SQL-Result}.
+	 * 
+	 * @param rs
+	 *            SQL-Result
+	 * @param projAttr
+	 *            nur diese Attribute des ResultSet werden in die
+	 *            FeatureCollection uebernommen (wenn nicht angegeben, werden
+	 *            ALLE Attribute uebernommen)
+	 * @throws SQLException
+	 *             falls der Zugriff auf die SQL-Metadaten scheitert
+	 * @throws SchemaException
+	 *             falls das Erzeugen des SimpleFeatureType scheitert
+	 * @throws IllegalAttributeException
+	 *             falls das Erzeugen eines Features scheitert
+	 */
+	public static FeatureCollection<SimpleFeatureType, SimpleFeature> createFeatureCollection(
+			ResultSet rs, String... projAttr) throws SchemaException,
+			IllegalAttributeException, SQLException {
+		// Schema der FeatureCollection erzeugen
+		SimpleFeatureType rsFeatureType = createFeatureType(rs.getMetaData(),
+				projAttr);
 
-      // Add an attribute for the column to the SimpleFeatureType
-      featureTypeFac.add( AttributeTypeFactory.newAttributeType(
-        columnName,
-        columnClass,
-        nillable,
-        null, // no restrictions
-        defaultValue,
-        null  // no meta data
-      ));
-    }
-    return featureTypeFac.buildFeatureType();
-  }
+		// Array fuer die Attribut-Werte eines Features
+		Object[] rsFeatureValues = new Object[rsFeatureType.getAttributeCount()];
 
-  /**
-   * Erzeugt einen {@link SimpleFeatureType} aus Beispiel-Attribut-Werten.
-   * @param  featureTypeName  Name fuer den SimpleFeatureType (kann {@code null} sein)
-   * @param  attrValues       Attribut-Werte
-   * @param  defaultAttrClass Standard-Typ, der fuer ein Attribut verwendet wird,
-   *                          wenn der angegebene Attribut-Wert {@code null} ist.
-   * @throws SchemaException falls das Erzeugen des SimpleFeatureType scheitert
-   */
-  public static SimpleFeatureType createFeatureType(String featureTypeName, Map<String,Object> attrValues,  Class defaultAttrClass) throws SchemaException  {
-    if ( featureTypeName == null )
-      featureTypeName = "SimpleFeatureType";
+		// ResultSet in FeatureCollection uebertragen
+		FeatureCollection<SimpleFeatureType, SimpleFeature> rsFeatureCollection = DefaultFeatureCollections
+				.newCollection();
+		for (; rs.next();) {
+			for (int i = 0; i < rsFeatureType.getAttributeCount(); i++)
+				rsFeatureValues[i] = rs.getObject(rsFeatureType
+						.getDescriptor(i).getName().getLocalPart());
+			rsFeatureCollection.add(createFeature(rsFeatureType,
+					rsFeatureValues));
+		}
 
-    SimpleFeatureTypeBuilder featureTypeFac = new SimpleFeatureTypeBuilder();
-    featureTypeFac.setName(featureTypeName);
-    for (String attrName : attrValues.keySet()) {
-      Object attrValue = attrValues.get( attrName );
-      Class  attrClass = attrValue == null ? defaultAttrClass : attrValue.getClass();
-      featureTypeFac.add( AttributeTypeFactory.newAttributeType(
-        attrName,
-        attrClass
-      ));
-    }
-    return featureTypeFac.buildFeatureType();
-  }
+		return rsFeatureCollection;
+	}
 
-  /**
-   * Creates a default {@link SimpleFeatureType} for a given
-   * Geometry class
-   * @param geomType
-   *            LineString.class, Point.class or Polygon.class from com.jts...
-   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-   *         Kr&uuml;ger</a>
-   */
-  public static SimpleFeatureType createFeatureType(final Class<?> geomType) {
-    // Create the only attribute
-    final AttributeDescriptor geometryAttribut = AttributeTypeFactory.newAttributeType("the_geom", geomType);
-    // Create the FeatureType with the only attribute
-    final SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
-    builder.setName( geomType.getSimpleName() );
-    builder.add(geometryAttribut);
-    return builder.buildFeatureType();
-  }
+	/**
+	 * Erzeugt einen {@link SimpleFeatureType} aus einem
+	 * {@linkplain ResultSetMetaData SQL-Result}.
+	 * 
+	 * @param metaData
+	 *            SQL-Metadaten des {@link ResultSet}
+	 * @param projAttr
+	 *            nur diese Attribute des ResultSet werden in den
+	 *            SimpleFeatureType uebernommen (wenn nicht angegeben, werden
+	 *            ALLE Attribute uebernommen)
+	 * @throws SQLException
+	 *             falls der Zugriff auf die SQL-Metadaten scheitert
+	 * @throws SchemaException
+	 *             falls das Erzeugen des SimpleFeatureType scheitert
+	 */
+	public static SimpleFeatureType createFeatureType(
+			ResultSetMetaData metaData, String... projAttr)
+			throws SQLException, SchemaException {
+		try {
+			return createFeatureType(metaData, null, Object.class, projAttr);
+		} catch (ClassNotFoundException err) {
+			// KANN NICHT VORKOMMEN, da Object.class als Standard-Klasse
+			// angegeben
+			// ist. Exception wird nur abgefangen, damit sie nicht in
+			// throw-clause
+			// deklariert (und in uebergeordneter Methode) abgefangen werden
+			// muss
+			return null;
+		}
+	}
 
-  /**
-   * Erzeugt einen Geometrie-Attribut-Typ.
-   * @param geomType  Art der Geometrie
-   * @param defGeom   Standard-Wert
-   * @param crs       Koordinatensystem
-   */
-  public static GeometryAttributeType createGeometryAttributeType(Class<? extends Geometry> geomType, Geometry defGeom, CoordinateReferenceSystem crs) {
-    return createGeometryAttributeType(null, geomType, defGeom, crs);
-  }
-  
-  /**
-   * Erzeugt einen Geometrie-Attribut-Typ.
-   * @param attrName  Name des attribute (wenn {@code null}, wird "the_geom"
-   *                  verwendet)
-   * @param geomType  Art der Geometrie
-   * @param defGeom   Standard-Wert
-   * @param crs       Koordinatensystem
-   */
-  public static GeometryAttributeType createGeometryAttributeType(String attrName, Class<? extends Geometry> geomType, Geometry defGeom, CoordinateReferenceSystem crs) {
-//    return new GeometricAttributeType(
-//        "the_geom",
-//        geomType,
-//        false,
-//        defGeom,
-//        crs,
-//        null
-//      );
-    if ( attrName == null )
-      attrName = "the_geom";
-    
-    return (GeometryAttributeType)AttributeTypeFactory.newAttributeType(
-        attrName,
-        geomType,
-        false, // nillable
-        null,  // restrictions
-        defGeom,
-        crs    // metadata used for CRS
-    );
-  }
+	/**
+	 * Erzeugt einen {@link SimpleFeatureType} aus einem {@linkplain ResultSet
+	 * SQL-Result}.
+	 * 
+	 * @param metaData
+	 *            SQL-Metadaten des {@link ResultSet}
+	 * @param featureTypeName
+	 *            Name fuer den SimpleFeatureType (kann {@code null} sein)
+	 * @param defaultAttrClass
+	 *            Klasse, die verwendet als Attribut-Typ wird, wenn die
+	 *            entsprechende Klasse des ResultSet nicht zur Verfuegung steht
+	 *            (wenn {@code null}, wird eine Exception geworfen)
+	 * @param projAttr
+	 *            nur diese Attribute des ResultSet werden in den
+	 *            SimpleFeatureType uebernommen (wenn nicht angegeben, werden
+	 *            ALLE Attribute uebernommen)
+	 * @throws SQLException
+	 *             falls der Zugriff auf die SQL-Metadaten scheitert
+	 * @throws SchemaException
+	 *             falls das Erzeugen des SimpleFeatureType scheitert
+	 * @throws ClassNotFoundException
+	 *             falls eine Attribut-Klasse aus dem ResultSet nicht erzeugt
+	 *             werden kann und keine Default-Klasse angegeben ist
+	 */
+	public static SimpleFeatureType createFeatureType(
+			ResultSetMetaData metaData, String featureTypeName,
+			Class defaultAttrClass, String... projAttr) throws SQLException,
+			SchemaException, ClassNotFoundException {
+		if (featureTypeName == null)
+			featureTypeName = "ResultSetFeatureType";
 
-  /**
-   * Returns a {@link SimpleFeatureBuilder} for a given schema from cache.
-   * If schema is not already used, a new builder is created and cached.
-   * @param schema the feature schema
-   * @param forceNewBuilder forces to create and cache a new builder instance
-   */
-  private static SimpleFeatureBuilder getFeatureBuilderFromCache(SimpleFeatureType schema, boolean forceNewBuilder) {
-    SimpleFeatureBuilder builder = featureBuilderCache.get(schema);
-    if ( builder == null || forceNewBuilder ) {
-      builder = new SimpleFeatureBuilder(schema);
-      featureBuilderCache.put(schema, builder);
-    }
-    return builder;
-  }
+		// Projektions-Attribute in ArrayList uebertragen
+		Set<String> projAttrList = new HashSet<String>();
+		for (String attrName : projAttr)
+			projAttrList.add(attrName);
 
-  /**
-   * Registriert einen {@link AutoValueGenerator} fuer einen {@link AttributeDescriptor}, so
-   * dass {@link #getNextAutoValue(AttributeDescriptor)} fuer diesen {@link AttributeDescriptor}
-   * verwendet werden kann.
-   * @param aType ein {@link AttributeDescriptor}
-   * @param generator generiert automatische Attribut-Werte
-   */
-  public static void registerAutoValueGenerator(AttributeDescriptor aType, AutoValueGenerator generator) {
-    autoAttrValueGenerators.put(aType, generator);
-  }
+		// Fuer alle Attribute aus Metadaten einen AttributeDescriptor erzeugen
+		// und diesen in SimpleFeatureType uebernehmen
+		SimpleFeatureTypeBuilder featureTypeFac = new SimpleFeatureTypeBuilder();
+		featureTypeFac.setName(featureTypeName);
+		for (int i = 1; i <= metaData.getColumnCount(); i++) {
+			String columnName = metaData.getColumnName(i);
+			// Attribut nur uebernehmen, wenn als Projektions-Attribut angegeben
+			if (projAttr.length > 0 && !projAttrList.contains(columnName))
+				continue;
 
-  /**
-   * Entfernt einen {@link AutoValueGenerator} fuer einen {@link AttributeDescriptor}.
-   * @param aType ein {@link AttributeDescriptor}
-   */
-  public static void unregisterAutoValueGenerator(AttributeDescriptor aType) {
-    if ( autoAttrValueGenerators.containsKey( aType ) )
-      autoAttrValueGenerators.remove(aType);
-  }
+			Class columnClass = defaultAttrClass;
+			try {
+				columnClass = Class.forName(metaData.getColumnClassName(i));
+			} catch (ClassNotFoundException err) {
+				if (defaultAttrClass == null)
+					throw err;
+				// Fehler Ignorieren und Object als Attribut-Klasse verwenden
+				LOGGER.warn("Column '" + columnName + "' (" + i + "): Class '"
+						+ metaData.getColumnClassName(i) + "' not found. '"
+						+ columnClass.getName() + "' used.");
+			}
+			boolean nillable = metaData.isNullable(i) != ResultSetMetaData.columnNoNulls;
+			Object defaultValue = getDefaultAttributeValue(columnClass);
+			if (defaultValue == null && !nillable)
+				LOGGER
+						.warn("Could not create default value for not-null attribute '"
+								+ columnName
+								+ "': "
+								+ columnClass.getSimpleName());
 
-  /**
-   * Liefert den {@link AutoValueGenerator} fuer einen {@link AttributeDescriptor}.
-   * @param aType ein {@link AttributeDescriptor}
-   * @return {@code null}, wenn fuer den {@link AttributeDescriptor} noch kein
-   *         {@link AutoValueGenerator} registriert worden ist
-   */
-  public static AutoValueGenerator getAutoValueGenerator(AttributeDescriptor aType) {
-    return autoAttrValueGenerators.get(aType);
-  }
+			// Add an attribute for the column to the SimpleFeatureType
+			featureTypeFac.add(AttributeTypeFactory.newAttributeType(
+					columnName, columnClass, nillable, null, // no restrictions
+					defaultValue, null // no meta data
+					));
+		}
+		return featureTypeFac.buildFeatureType();
+	}
 
-  /**
-   * Liefert den naechsten Auto-Wert fuer einen {@link AttributeDescriptor}.
-   * @param aType ein {@link AttributeDescriptor}
-   * @exception UnsupportedOperationException falls fuer das Attribut noch
-   *            kein {@link AutoValueGenerator} registriert ist
-   */
-  public static Object getNextAutoValue(AttributeDescriptor aType) {
-    AutoValueGenerator<?> avg = getAutoValueGenerator(aType);
-    if ( avg == null )
-      throw new UnsupportedOperationException("No AutoValueGenerator registered for attribute type: "+aType.getLocalName());
-    return avg.getNextValue();
-  }
-    
-  /**
-   * Creates a new feature for a given schema.
-   * @param schema     schema for the feature
-   * @param forceNewBuilder forces the creation of a new {@link SimpleFeatureBuilder}
-   * @param fID        feature id for the new feature
-   * @param attrValues values of the attributes
-   */
-  public static SimpleFeature createFeature(SimpleFeatureType schema, boolean forceNewBuilder, String fID, Object... attrValues) {
-    SimpleFeatureBuilder builder = getFeatureBuilderFromCache(schema, forceNewBuilder);
-    return builder.buildFeature(fID, attrValues);
-  }
-  
-  /**
-   * Creates a new feature for a given schema.
-   * @param schema     schema for the feature
-   * @param fID        feature id for the new feature
-   * @param attrValues values of the attributes
-   */
-  public static SimpleFeature createFeature(SimpleFeatureType schema, String fID, Object... attrValues) {
-    return createFeature(schema, false, fID, attrValues);
-  }
+	/**
+	 * Erzeugt einen {@link SimpleFeatureType} aus Beispiel-Attribut-Werten.
+	 * 
+	 * @param featureTypeName
+	 *            Name fuer den SimpleFeatureType (kann {@code null} sein)
+	 * @param attrValues
+	 *            Attribut-Werte
+	 * @param defaultAttrClass
+	 *            Standard-Typ, der fuer ein Attribut verwendet wird, wenn der
+	 *            angegebene Attribut-Wert {@code null} ist.
+	 * @throws SchemaException
+	 *             falls das Erzeugen des SimpleFeatureType scheitert
+	 */
+	public static SimpleFeatureType createFeatureType(String featureTypeName,
+			Map<String, Object> attrValues, Class defaultAttrClass)
+			throws SchemaException {
+		if (featureTypeName == null)
+			featureTypeName = "SimpleFeatureType";
 
-  /**
-   * Creates a new feature for a given schema with a random generated id.
-   * @param schema     schema for the feature
-   * @param attrValues values of the attributes
-   */
-  public static SimpleFeature createFeature(SimpleFeatureType schema, Object... attrValues) {
-    return createFeature(
-        schema,
-        "FID_" + new Random().nextInt(),
-        attrValues
-    );
-  }
-  
+		SimpleFeatureTypeBuilder featureTypeFac = new SimpleFeatureTypeBuilder();
+		featureTypeFac.setName(featureTypeName);
+		for (String attrName : attrValues.keySet()) {
+			Object attrValue = attrValues.get(attrName);
+			Class attrClass = attrValue == null ? defaultAttrClass : attrValue
+					.getClass();
+			featureTypeFac.add(AttributeTypeFactory.newAttributeType(attrName,
+					attrClass));
+		}
+		return featureTypeFac.buildFeatureType();
+	}
+
 	/**
-	 * Creates a sample SimpleFeature instance of the given {@link SimpleFeatureType}
+	 * Creates a default {@link SimpleFeatureType} for a given Geometry class
+	 * 
+	 * @param geomType
+	 *            LineString.class, Point.class or Polygon.class from com.jts...
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static SimpleFeatureType createFeatureType(final Class<?> geomType) {
+		// Create the only attribute
+		final AttributeDescriptor geometryAttribut = AttributeTypeFactory
+				.newAttributeType("the_geom", geomType);
+		// Create the FeatureType with the only attribute
+		final SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
+		builder.setName(geomType.getSimpleName());
+		builder.add(geometryAttribut);
+		return builder.buildFeatureType();
+	}
+
+	/**
+	 * Erzeugt einen Geometrie-Attribut-Typ.
+	 * 
+	 * @param geomType
+	 *            Art der Geometrie
+	 * @param defGeom
+	 *            Standard-Wert
+	 * @param crs
+	 *            Koordinatensystem
+	 */
+	public static GeometryAttributeType createGeometryAttributeType(
+			Class<? extends Geometry> geomType, Geometry defGeom,
+			CoordinateReferenceSystem crs) {
+		return createGeometryAttributeType(null, geomType, defGeom, crs);
+	}
+
+	/**
+	 * Erzeugt einen Geometrie-Attribut-Typ.
+	 * 
+	 * @param attrName
+	 *            Name des attribute (wenn {@code null}, wird "the_geom"
+	 *            verwendet)
+	 * @param geomType
+	 *            Art der Geometrie
+	 * @param defGeom
+	 *            Standard-Wert
+	 * @param crs
+	 *            Koordinatensystem
+	 */
+	public static GeometryAttributeType createGeometryAttributeType(
+			String attrName, Class<? extends Geometry> geomType,
+			Geometry defGeom, CoordinateReferenceSystem crs) {
+		// return new GeometricAttributeType(
+		// "the_geom",
+		// geomType,
+		// false,
+		// defGeom,
+		// crs,
+		// null
+		// );
+		if (attrName == null)
+			attrName = "the_geom";
+
+		return (GeometryAttributeType) AttributeTypeFactory.newAttributeType(
+				attrName, geomType, false, // nillable
+				null, // restrictions
+				defGeom, crs // metadata used for CRS
+				);
+	}
+
+	/**
+	 * Returns a {@link SimpleFeatureBuilder} for a given schema from cache. If
+	 * schema is not already used, a new builder is created and cached.
+	 * 
 	 * @param schema
+	 *            the feature schema
+	 * @param forceNewBuilder
+	 *            forces to create and cache a new builder instance
+	 */
+	private static SimpleFeatureBuilder getFeatureBuilderFromCache(
+			SimpleFeatureType schema, boolean forceNewBuilder) {
+		SimpleFeatureBuilder builder = featureBuilderCache.get(schema);
+		if (builder == null || forceNewBuilder) {
+			builder = new SimpleFeatureBuilder(schema);
+			featureBuilderCache.put(schema, builder);
+		}
+		return builder;
+	}
+
+	/**
+	 * Registriert einen {@link AutoValueGenerator} fuer einen
+	 * {@link AttributeDescriptor}, so dass
+	 * {@link #getNextAutoValue(AttributeDescriptor)} fuer diesen
+	 * {@link AttributeDescriptor} verwendet werden kann.
+	 * 
+	 * @param aType
+	 *            ein {@link AttributeDescriptor}
+	 * @param generator
+	 *            generiert automatische Attribut-Werte
+	 */
+	public static void registerAutoValueGenerator(AttributeDescriptor aType,
+			AutoValueGenerator generator) {
+		autoAttrValueGenerators.put(aType, generator);
+	}
+
+	/**
+	 * Entfernt einen {@link AutoValueGenerator} fuer einen
+	 * {@link AttributeDescriptor}.
+	 * 
+	 * @param aType
+	 *            ein {@link AttributeDescriptor}
+	 */
+	public static void unregisterAutoValueGenerator(AttributeDescriptor aType) {
+		if (autoAttrValueGenerators.containsKey(aType))
+			autoAttrValueGenerators.remove(aType);
+	}
+
+	/**
+	 * Liefert den {@link AutoValueGenerator} fuer einen
+	 * {@link AttributeDescriptor}.
+	 * 
+	 * @param aType
+	 *            ein {@link AttributeDescriptor}
+	 * @return {@code null}, wenn fuer den {@link AttributeDescriptor} noch kein
+	 *         {@link AutoValueGenerator} registriert worden ist
+	 */
+	public static AutoValueGenerator getAutoValueGenerator(
+			AttributeDescriptor aType) {
+		return autoAttrValueGenerators.get(aType);
+	}
+
+	/**
+	 * Liefert den naechsten Auto-Wert fuer einen {@link AttributeDescriptor}.
+	 * 
+	 * @param aType
+	 *            ein {@link AttributeDescriptor}
+	 * @exception UnsupportedOperationException
+	 *                falls fuer das Attribut noch kein
+	 *                {@link AutoValueGenerator} registriert ist
+	 */
+	public static Object getNextAutoValue(AttributeDescriptor aType) {
+		AutoValueGenerator<?> avg = getAutoValueGenerator(aType);
+		if (avg == null)
+			throw new UnsupportedOperationException(
+					"No AutoValueGenerator registered for attribute type: "
+							+ aType.getLocalName());
+		return avg.getNextValue();
+	}
+
+	/**
+	 * Creates a new feature for a given schema.
+	 * 
+	 * @param schema
+	 *            schema for the feature
+	 * @param forceNewBuilder
+	 *            forces the creation of a new {@link SimpleFeatureBuilder}
+	 * @param fID
+	 *            feature id for the new feature
+	 * @param attrValues
+	 *            values of the attributes
+	 */
+	public static SimpleFeature createFeature(SimpleFeatureType schema,
+			boolean forceNewBuilder, String fID, Object... attrValues) {
+		SimpleFeatureBuilder builder = getFeatureBuilderFromCache(schema,
+				forceNewBuilder);
+		return builder.buildFeature(fID, attrValues);
+	}
+
+	/**
+	 * Creates a new feature for a given schema.
+	 * 
+	 * @param schema
+	 *            schema for the feature
+	 * @param fID
+	 *            feature id for the new feature
+	 * @param attrValues
+	 *            values of the attributes
+	 */
+	public static SimpleFeature createFeature(SimpleFeatureType schema,
+			String fID, Object... attrValues) {
+		return createFeature(schema, false, fID, attrValues);
+	}
+
+	/**
+	 * Creates a new feature for a given schema with a random generated id.
+	 * 
+	 * @param schema
+	 *            schema for the feature
+	 * @param attrValues
+	 *            values of the attributes
+	 */
+	public static SimpleFeature createFeature(SimpleFeatureType schema,
+			Object... attrValues) {
+		return createFeature(schema, "FID_" + new Random().nextInt(),
+				attrValues);
+	}
+
+	/**
+	 * Creates a sample SimpleFeature instance of the given
+	 * {@link SimpleFeatureType}
+	 * 
+	 * @param schema
 	 *            the schema for which to create a sample SimpleFeature instance
 	 * @author SK
 	 * @throws org.opengis.feature.IllegalAttributeException
@@ -1379,8 +1743,9 @@
 
 		try {
 			SimpleFeatureBuilder builder = new SimpleFeatureBuilder(schema);
-			sampleFeature = builder.buildFeature( "createSampleFeature_"+new Random().nextInt() );
-			
+			sampleFeature = builder.buildFeature("createSampleFeature_"
+					+ new Random().nextInt());
+
 		} catch (org.opengis.feature.IllegalAttributeException e) {
 			// Thrown if the SimpleFeatureType does not validate the attributes
 			// Not very likely if we just create a sample feature, so we make it
@@ -1392,71 +1757,166 @@
 	}
 
 	/**
-	 * Erstellt eine {@link FeatureSource} basierend auf einem {@link MemoryDataStore} für eine übergebene {@link FeatureCollection}
-	 * @param features 
+	 * Erstellt eine {@link FeatureSource} basierend auf einem
+	 * {@link MemoryDataStore} für eine übergebene {@link FeatureCollection}
+	 * 
+	 * @param features
 	 */
 	public static FeatureSource<SimpleFeatureType, SimpleFeature> createMemoryFeatureSource(
 			FeatureCollection<SimpleFeatureType, SimpleFeature> features) {
 		try {
-			return  new MemoryDataStore(
-					features).getFeatureSource(features
+			return new MemoryDataStore(features).getFeatureSource(features
 					.getSchema().getTypeName());
 		} catch (IOException e) {
-			LOGGER.error("Creating a memory datastore for the allFeaturesCollection", e);
-			throw new RuntimeException("Creating a memory datastore for the allFeaturesCollection",e);
+			LOGGER
+					.error(
+							"Creating a memory datastore for the allFeaturesCollection",
+							e);
+			throw new RuntimeException(
+					"Creating a memory datastore for the allFeaturesCollection",
+					e);
 		}
 	}
 
+	/**
+	 * Liefert das Objekt ({@link GridCoverage2D} oder {@link FeatureCollection}
+	 * oder GridCoverager oder {@link GridCoverageReader} auf dem ein Layer
+	 * basiert. Ein Raster-Layer zeichnen sich dadurch aus, dass die zugrunde
+	 * liegende {@link FeatureCollection} nur ein SimpleFeature enthaelt, das
+	 * genau ein Attribut mit Namen "GridCoverage" und Typ {@code
+	 * GridCoverage2D} oder {@link AbstractGridCoverageReader} hat. Sind diese
+	 * Bedingungen erfuellt, wird das 2. Attribut zurueckgegeben, ansonsten die
+	 * {@link FeatureCollection}.
+	 * 
+	 * @see {@link FeatureUtilities#wrapGridCoverage(GridCoverage2D)} and
+	 *      {@link FeatureUtilities#wrapGridCoverageReader(AbstractGridCoverage2DReader, GeneralParameterValue[])}
+	 * 
+	 * @param layer
+	 *            ein Layer
+	 * @return {@code null}, falls das Objekt nicht ermittelt werden kann (da
+	 *         ein Fehler aufgetreten ist).
+	 * @param featureSource
+	 * @return
+	 */
+	public static Object getWrappedGeoObject(
+			FeatureSource<SimpleFeatureType, SimpleFeature> featureSource) {
+		try {
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fc = featureSource
+					.getFeatures();
+			return getWrappedGeoObject(fc);
 
+		} catch (Exception err) {
+			LOGGER.warn(err.getMessage(), err);
+			return null;
+		}
+	}
 
-//  /**
-//   * Extrahiert alle Geometrien aus einer FeatureCollection. Fuer jedes
-//   * Geometry-Attribut der FeatureCollection wird eine GeometrieCollection
-//   * (<code>JTSGeometries</code>) angelegt, in der die Geometrien des jeweiligen
-//   * Attributs zusammengefasst werden.
-//   * @param fc FeatureCollection
-//   * @return Array aller Geometrien im SimpleFeature.
-//   * @see org.geotools.feature.FeatureCollection
-//   * @see org.geotools.renderer.geom.JTSGeometries
-//   */
-//  public static GeometryCollection[] extractGeometriesToGeometryCollection(FeatureCollection fc) throws org.opengis.referencing.operation.TransformException{
-//    FeatureIterator it        = fc.features(); // Zeiger durch die einzelnen Features
-//    Vector          gcVec     = new Vector();  // Speichert die Collections
-//    int             nextGCIdx = 0;             // verweist innerhaln eines Features
-//                                               // auf die naechste zu verwendende
-//                                               // Collection
-//
-//    // alle Features nach Geometrien durchsuchen
-//    for (int i=0; it.hasNext(); i++) {
-//      SimpleFeature f = it.next();
-//
-//      // Das erste Geometry-Attribut des Features wird in GeometryCollection
-//      // eins gespeichert, das zweite in der zweiten, usw.
-//      // Bei jedem SimpleFeature wird also wieder von vorne begonnen.
-//      nextGCIdx = 0;
-//
-//      // Alle Attribute auf Geometrien checken
-//      for (int j=0; j<f.getFeatureType().getAttributeCount(); j++) {
-//        // Handelt es sich um eine Geometrie, wird sie in einer
-//        // GeometryCollection gespeichert (fuer jedes Geometry-Attr.
-//        // gibt es eine eigene Collection!!)
-////        if ( f.getFeatureType().getAttributeType(j).isGeometry() ){
-//        if ( f.getFeatureType() instanceof GeometryAttributeType ) {
-//          // gibt es noch keine Collection fuer das Attr., wird eine
-//          // neue erstellt
-//          if ( nextGCIdx >= gcVec.size() )
-//            gcVec.add( new JTSGeometries() );
-//          // Geometrie in Collection einfuegen
-//          ((JTSGeometries)gcVec.elementAt(nextGCIdx++)).add((Geometry)f.getAttribute(j));
-//        }
-//      }
-//    }
-//
-//    GeometryCollection[] gcArr = new GeometryCollection[gcVec.size()];
-//    for (int i=0; i<gcVec.size(); i++)
-//      gcArr[i] = (GeometryCollection)gcVec.elementAt(i);
-//    return gcArr;
-//  }
-  
+	/**
+	 * Liefert das Objekt ({@link GridCoverage2D} oder {@link FeatureCollection}
+	 * oder GridCoverager oder {@link GridCoverageReader} auf dem ein Layer
+	 * basiert. Ein Raster-Layer zeichnen sich dadurch aus, dass die zugrunde
+	 * liegende {@link FeatureCollection} nur ein SimpleFeature enthaelt, das
+	 * genau ein Attribut mit Namen "GridCoverage" und Typ {@code
+	 * GridCoverage2D} oder {@link AbstractGridCoverageReader} hat. Sind diese
+	 * Bedingungen erfuellt, wird das 2. Attribut zurueckgegeben, ansonsten die
+	 * {@link FeatureCollection}.
+	 * 
+	 * @see {@link FeatureUtilities#wrapGridCoverage(GridCoverage2D)} and
+	 *      {@link FeatureUtilities#wrapGridCoverageReader(AbstractGridCoverage2DReader, GeneralParameterValue[])}
+	 * 
+	 * @param layer
+	 *            ein Layer
+	 * @return {@code null}, falls das Objekt nicht ermittelt werden kann (da
+	 *         ein Fehler aufgetreten ist).
+	 * @param featureSource
+	 * @return
+	 */
+	public static Object getWrappedGeoObject(
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fc) {
+
+		try {
+
+			// RasterLayer muss genau ein SimpleFeature beinhalten
+			// Ist dies nicht der Fall wird die FeatureCollection zurueckgegeben
+			if (fc == null || fc.size() != 1) {
+				return fc;
+			}
+
+			// Ist dies nicht der Fall wird die FeatureCollection zurueckgegeben
+			SimpleFeatureType ftype = fc.getSchema();
+
+			if (ftype == null || !GC_NAME.equals(ftype.getName()))
+				return fc;
+
+			FeatureIterator<SimpleFeature> fIt = fc.features();
+
+			try {
+				SimpleFeature onlyFeature = fIt.next();
+
+				// GridCoverage2D or ImagePyramidReader
+				return onlyFeature.getAttribute(1);
+
+			} finally {
+				fIt.close();
+			}
+
+		} catch (Exception err) {
+			LOGGER.warn(err.getMessage(), err);
+			return null;
+		}
+	}
+
+	// /**
+	// * Extrahiert alle Geometrien aus einer FeatureCollection. Fuer jedes
+	// * Geometry-Attribut der FeatureCollection wird eine GeometrieCollection
+	// * (<code>JTSGeometries</code>) angelegt, in der die Geometrien des
+	// jeweiligen
+	// * Attributs zusammengefasst werden.
+	// * @param fc FeatureCollection
+	// * @return Array aller Geometrien im SimpleFeature.
+	// * @see org.geotools.feature.FeatureCollection
+	// * @see org.geotools.renderer.geom.JTSGeometries
+	// */
+	// public static GeometryCollection[]
+	// extractGeometriesToGeometryCollection(FeatureCollection fc) throws
+	// org.opengis.referencing.operation.TransformException{
+	// FeatureIterator it = fc.features(); // Zeiger durch die einzelnen
+	// Features
+	// Vector gcVec = new Vector(); // Speichert die Collections
+	// int nextGCIdx = 0; // verweist innerhaln eines Features
+	// // auf die naechste zu verwendende
+	// // Collection
+	//
+	// // alle Features nach Geometrien durchsuchen
+	// for (int i=0; it.hasNext(); i++) {
+	// SimpleFeature f = it.next();
+	//
+	// // Das erste Geometry-Attribut des Features wird in GeometryCollection
+	// // eins gespeichert, das zweite in der zweiten, usw.
+	// // Bei jedem SimpleFeature wird also wieder von vorne begonnen.
+	// nextGCIdx = 0;
+	//
+	// // Alle Attribute auf Geometrien checken
+	// for (int j=0; j<f.getFeatureType().getAttributeCount(); j++) {
+	// // Handelt es sich um eine Geometrie, wird sie in einer
+	// // GeometryCollection gespeichert (fuer jedes Geometry-Attr.
+	// // gibt es eine eigene Collection!!)
+	// // if ( f.getFeatureType().getAttributeType(j).isGeometry() ){
+	// if ( f.getFeatureType() instanceof GeometryAttributeType ) {
+	// // gibt es noch keine Collection fuer das Attr., wird eine
+	// // neue erstellt
+	// if ( nextGCIdx >= gcVec.size() )
+	// gcVec.add( new JTSGeometries() );
+	// // Geometrie in Collection einfuegen
+	// ((JTSGeometries)gcVec.elementAt(nextGCIdx++)).add((Geometry)f.getAttribute(j));
+	// }
+	// }
+	// }
+	//
+	// GeometryCollection[] gcArr = new GeometryCollection[gcVec.size()];
+	// for (int i=0; i<gcVec.size(); i++)
+	// gcArr[i] = (GeometryCollection)gcVec.elementAt(i);
+	// return gcArr;
+	// }
+
 }
-

Modified: branches/1.0-gt2-2.6/src/schmitzm/geotools/gui/GridPanelFormatter.java
===================================================================
--- branches/1.0-gt2-2.6/src/schmitzm/geotools/gui/GridPanelFormatter.java	2009-09-30 15:36:39 UTC (rev 419)
+++ branches/1.0-gt2-2.6/src/schmitzm/geotools/gui/GridPanelFormatter.java	2009-10-01 20:22:48 UTC (rev 420)
@@ -158,12 +158,18 @@
 	public void setCRS(CoordinateReferenceSystem crs) {
 		this.crs = crs;
 	}
-	
+
 	/**
-	 * Returns a tooltip String to applied to the {@link GridPanel}s. May be <code>null</code> 
+	 * Returns a tooltip String to applied to the {@link GridPanel}s. May be
+	 * <code>null</code>
 	 */
-	public String getTooltip(){
-		return RESOURCE.getString("schmitzm.geotools.gui.GridPanelFormatter.ToolTipTemplate", GeotoolsGUIUtil.getTitleForCRS(getCRS()), CRSUtilities.getUnit(getCRS().getCoordinateSystem()));
+	public String getTooltip() {
+		if (crs == null)
+			return null;
+		return RESOURCE.getString(
+				"schmitzm.geotools.gui.GridPanelFormatter.ToolTipTemplate",
+				GeotoolsGUIUtil.getTitleForCRS(crs), CRSUtilities.getUnit(crs
+						.getCoordinateSystem()));
 	}
 
 }

Modified: branches/1.0-gt2-2.6/src/schmitzm/geotools/gui/JMapPane.java
===================================================================
--- branches/1.0-gt2-2.6/src/schmitzm/geotools/gui/JMapPane.java	2009-09-30 15:36:39 UTC (rev 419)
+++ branches/1.0-gt2-2.6/src/schmitzm/geotools/gui/JMapPane.java	2009-10-01 20:22:48 UTC (rev 420)
@@ -82,6 +82,7 @@
 import org.geotools.renderer.lite.RendererUtilities;
 import org.geotools.renderer.lite.StreamingRenderer;
 import org.geotools.renderer.shape.ShapefileRenderer;
+import org.geotools.resources.coverage.FeatureUtilities;
 import org.geotools.resources.image.ImageUtilities;
 import org.geotools.styling.Style;
 import org.geotools.swing.event.MapMouseEvent;
@@ -101,6 +102,7 @@
 
 import schmitzm.geotools.FilterUtil;
 import schmitzm.geotools.JTSUtil;
+import schmitzm.geotools.feature.FeatureUtil;
 import schmitzm.geotools.grid.GridUtil;
 import schmitzm.geotools.io.GeoImportUtil;
 import schmitzm.geotools.map.event.FeatureSelectedEvent;
@@ -165,9 +167,6 @@
  */
 public class JMapPane extends gtmig.org.geotools.swing.JMapPane {
 
-	private static final NameImpl GC_NAME = new NameImpl(
-			"http://www.opengis.net/gml", "GridCoverage");
-
 	/**
 	 * SK: Nach dem Drag, soll die {@link GeoMapPane} erfahren, dass die Area
 	 * veraendert wurde.
@@ -2178,46 +2177,17 @@
 	 * wird das 2. Attribut zurueckgegeben, ansonsten die
 	 * {@link FeatureCollection}.
 	 * 
+	 * @see {@link FeatureUtilities#wrapGridCoverage(GridCoverage2D)} and {@link FeatureUtilities#wrapGridCoverageReader(AbstractGridCoverage2DReader, GeneralParameterValue[])} 
+	 * 
 	 * @param layer
 	 *            ein Layer
 	 * @return {@code null}, falls das Objekt nicht ermittelt werden kann (da
 	 *         ein Fehler aufgetreten ist).
 	 */
 	public static Object getLayerSourceObject(MapLayer layer) {
-		try {
-			final FeatureSource<SimpleFeatureType, SimpleFeature> featureSource = (FeatureSource<SimpleFeatureType, SimpleFeature>) layer
-					.getFeatureSource();
-			FeatureCollection<SimpleFeatureType, SimpleFeature> fc = featureSource
-					.getFeatures();
+		return FeatureUtil.getWrappedGeoObject((FeatureSource<SimpleFeatureType, SimpleFeature>) layer
+				.getFeatureSource());
 
-			// RasterLayer muss genau ein SimpleFeature beinhalten
-			// Ist dies nicht der Fall wird die FeatureCollection zurueckgegeben
-			if (fc == null || fc.size() != 1) {
-				return fc;
-			}
-
-			// Ist dies nicht der Fall wird die FeatureCollection zurueckgegeben
-			SimpleFeatureType ftype = fc.getSchema(); 
-
-			if (ftype == null || !GC_NAME.equals(ftype.getName()))
-				return fc;
-
-			FeatureIterator<SimpleFeature> fIt = fc.features();
-
-			try {
-				SimpleFeature onlyFeature = fIt.next();
-				
-				// GridCoverage2D or ImagePyramidReader
-				return onlyFeature.getAttribute(1);
-
-			} finally {
-				fIt.close();
-			}
-			
-		} catch (Exception err) {
-			LOGGER.warn(err.getMessage(), err);
-			return null;
-		}
 	}
 
 	/**

Modified: branches/1.0-gt2-2.6/src/schmitzm/io/IOUtil.java
===================================================================
--- branches/1.0-gt2-2.6/src/schmitzm/io/IOUtil.java	2009-09-30 15:36:39 UTC (rev 419)
+++ branches/1.0-gt2-2.6/src/schmitzm/io/IOUtil.java	2009-10-01 20:22:48 UTC (rev 420)
@@ -518,6 +518,7 @@
 		try {
 			f = new File(url.toURI());
 		} catch (Exception e) {
+			// TODO Here we probably need more cases...
 			f = new File(url.getPath().replace("%20", " "));
 		}
 //		LOGGER.debug("        to " + f.toString());

Modified: branches/1.0-gt2-2.6/src/skrueger/AttributeMetaData.java
===================================================================
--- branches/1.0-gt2-2.6/src/skrueger/AttributeMetaData.java	2009-09-30 15:36:39 UTC (rev 419)
+++ branches/1.0-gt2-2.6/src/skrueger/AttributeMetaData.java	2009-10-01 20:22:48 UTC (rev 420)
@@ -31,6 +31,7 @@
 
 import org.apache.log4j.Logger;
 
+import skrueger.geotools.Copyable;
 import skrueger.geotools.StyledLayerInterface;
 import skrueger.i8n.Translation;
 
@@ -40,7 +41,7 @@
  *
  * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
  */
-public class AttributeMetaData {
+public class AttributeMetaData implements Copyable<AttributeMetaData>{
 	static private final Logger LOGGER = Logger
 			.getLogger(AttributeMetaData.class);
 	protected Translation title = new Translation();
@@ -48,7 +49,7 @@
 	protected boolean visible = false;
 	protected String unit = "";
 	protected int colIdx;
-
+	
 	/**
 	 * Creates an {@link AttributeMetaData} object with the following information
 	 * @param colIdx The column index of this attribute in the underlying table/dbf/etc...
@@ -78,7 +79,11 @@
 		this(col, true, new Translation(defaultName), new Translation(), "");
 	}
 
-	public Boolean isVisible() {
+	/** Only used for {@link Copyable<AttributeMetaData>#copy()}**/
+	private AttributeMetaData() {
+	}
+
+	public boolean isVisible() {
 		return visible;
 	}
 
@@ -114,4 +119,31 @@
 	public void setUnit(final String unit) {
 		this.unit = unit;
 	}
+
+	@Override
+	public AttributeMetaData copyTo(AttributeMetaData amd) {
+		getTitle().copyTo(amd.getTitle());
+		getDesc().copyTo(amd.getDesc());
+		amd.setUnit(getUnit());
+		amd.setVisible(isVisible());
+		amd.setColIdx(getColIdx());
+		
+		return amd;
+	}
+
+	@Override
+	public AttributeMetaData copy() {
+		AttributeMetaData amd = new AttributeMetaData();
+		getTitle().copyTo(amd.getTitle());
+		getDesc().copyTo(amd.getDesc());
+		amd.setUnit(getUnit());
+		amd.setVisible(isVisible());
+		amd.setColIdx(getColIdx());
+		
+		return amd;
+	}
+
+	private void setColIdx(int colIdx_) {
+		colIdx = colIdx_;
+	}
 }

Added: branches/1.0-gt2-2.6/src/skrueger/geotools/AttributeMetadataMap.java
===================================================================
--- branches/1.0-gt2-2.6/src/skrueger/geotools/AttributeMetadataMap.java	2009-09-30 15:36:39 UTC (rev 419)
+++ branches/1.0-gt2-2.6/src/skrueger/geotools/AttributeMetadataMap.java	2009-10-01 20:22:48 UTC (rev 420)
@@ -0,0 +1,36 @@
+package skrueger.geotools;
+
+import java.util.TreeMap;
+
+import skrueger.AttributeMetaData;
+
+/**
+ * An extension of TreeMap, that is clonable in the sense of
+ * 
+ * @author stefan
+ * 
+ */
+public class AttributeMetadataMap extends TreeMap<Integer, AttributeMetaData>
+		implements Copyable<AttributeMetadataMap> {
+
+	public AttributeMetadataMap() {
+	}
+
+	@Override
+	public AttributeMetadataMap copyTo(AttributeMetadataMap amdMap) {
+		
+		amdMap.clear();
+		
+		for (Integer key : keySet()) {
+			AttributeMetaData attributeMetaData = get(key);
+			amdMap.put(key, attributeMetaData.copy());
+		}
+		return amdMap;
+	}
+
+	@Override
+	public AttributeMetadataMap copy() {
+		AttributeMetadataMap copy = new AttributeMetadataMap();
+		return copyTo(copy);
+	}
+}


Property changes on: branches/1.0-gt2-2.6/src/skrueger/geotools/AttributeMetadataMap.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Id URL
Name: svn:eol-style
   + native

Added: branches/1.0-gt2-2.6/src/skrueger/geotools/Copyable.java
===================================================================
--- branches/1.0-gt2-2.6/src/skrueger/geotools/Copyable.java	2009-09-30 15:36:39 UTC (rev 419)
+++ branches/1.0-gt2-2.6/src/skrueger/geotools/Copyable.java	2009-10-01 20:22:48 UTC (rev 420)
@@ -0,0 +1,19 @@
+package skrueger.geotools;
+
+
+
+public interface Copyable<T> {
+	
+	/**
+	 * Deep copy this obejct to the target object. The target object has to be of the same  
+	 * @param t
+	 */
+	T copyTo (T t);
+
+	/**
+	 * Creates a new instance of T and copies all values.  
+	 * @param t
+	 */
+	T copy();
+	
+}


Property changes on: branches/1.0-gt2-2.6/src/skrueger/geotools/Copyable.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Id URL
Name: svn:eol-style
   + native

Modified: branches/1.0-gt2-2.6/src/skrueger/geotools/StyledFS.java
===================================================================
--- branches/1.0-gt2-2.6/src/skrueger/geotools/StyledFS.java	2009-09-30 15:36:39 UTC (rev 419)
+++ branches/1.0-gt2-2.6/src/skrueger/geotools/StyledFS.java	2009-10-01 20:22:48 UTC (rev 420)
@@ -35,7 +35,6 @@
 import java.net.URL;
 import java.util.Date;
 import java.util.HashMap;
-import java.util.Map;
 import java.util.Random;
 
 import javax.swing.ImageIcon;
@@ -81,7 +80,7 @@
 
 	private File sldFile;
 
-	private HashMap<Integer, AttributeMetaData> map;
+	private AttributeMetadataMap map;
 
 	/**
 	 * This class enables a non Atlas context to use the Atlas LayerPanel
@@ -226,10 +225,10 @@
 	/**
 	 * 
 	 */
-	public Map<Integer, AttributeMetaData> getAttributeMetaDataMap() {
+	public AttributeMetadataMap getAttributeMetaDataMap() {
 		if (map == null) {
 
-			map = new HashMap<Integer, AttributeMetaData>();
+			map = new AttributeMetadataMap();
 
 			// Leaving out the first one, it will be the_geom
 			for (int i = 1; i < fs.getSchema().getAttributeCount(); i++) {

Modified: branches/1.0-gt2-2.6/src/skrueger/geotools/StyledFeatureCollection.java
===================================================================
--- branches/1.0-gt2-2.6/src/skrueger/geotools/StyledFeatureCollection.java	2009-09-30 15:36:39 UTC (rev 419)
+++ branches/1.0-gt2-2.6/src/skrueger/geotools/StyledFeatureCollection.java	2009-10-01 20:22:48 UTC (rev 420)
@@ -63,7 +63,7 @@
 		StyledFeatureCollectionInterface {
 
 	/** Holds the meta data for displaying a legend. */
-	protected Map<Integer, AttributeMetaData> attrMetaData = null;
+	protected AttributeMetadataMap attrMetaData = null;
 
 	/**
 	 * We be filled with a "virtual" {@link FeatureSource} on demand.
@@ -95,7 +95,7 @@
 	 */
 	public StyledFeatureCollection(FeatureCollection<SimpleFeatureType,SimpleFeature> fc, String id,
 			Translation title, Translation desc, Translation keywords,
-			Style style, Map<Integer, AttributeMetaData> attrMetaData,
+			Style style, AttributeMetadataMap attrMetaData,
 			ImageIcon icon) {
 		super(fc, fc.getBounds(), fc.getSchema().getGeometryDescriptor()
 				.getCoordinateReferenceSystem(), id, title, desc, keywords, style, icon);
@@ -125,7 +125,7 @@
 	 */
 	public StyledFeatureCollection(FeatureCollection<SimpleFeatureType,SimpleFeature> fc, String id,
 			Translation title, Translation desc, Translation keywords,
-			StyledLayerStyle<Map<Integer, AttributeMetaData>> style,
+			StyledLayerStyle<AttributeMetadataMap> style,
 			ImageIcon icon) {
 		super(fc, fc.getBounds(), fc.getSchema().getGeometryDescriptor()
 				.getCoordinateReferenceSystem(), id, title, desc, keywords,
@@ -180,7 +180,7 @@
 	 */
 	public StyledFeatureCollection(FeatureCollection<SimpleFeatureType,SimpleFeature> fc, String id,
 			String title, String desc, String keywords, Style style,
-			Map<Integer, AttributeMetaData> attrMetaData, ImageIcon icon) {
+			AttributeMetadataMap attrMetaData, ImageIcon icon) {
 		this(fc, id, (Translation) null, null, null, style, attrMetaData, icon);
 		setTitle(title);
 		setDesc(desc);
@@ -210,7 +210,7 @@
 	 */
 	public StyledFeatureCollection(FeatureCollection<SimpleFeatureType,SimpleFeature> fc, String id,
 			String title, String desc, String keywords,
-			StyledLayerStyle<Map<Integer, AttributeMetaData>> style,
+			StyledLayerStyle<AttributeMetadataMap> style,
 			ImageIcon icon) {
 		this(fc, id, title, desc, keywords, style != null ? style
 				.getGeoObjectStyle() : null, style != null ? style
@@ -257,7 +257,7 @@
 	 * @see #createDefaultAttributeMetaDataMap(FeatureCollection)
 	 */
 	public StyledFeatureCollection(FeatureCollection<SimpleFeatureType,SimpleFeature> fc, String id,
-			String title, StyledLayerStyle<Map<Integer, AttributeMetaData>> style) {
+			String title, StyledLayerStyle<AttributeMetadataMap> style) {
 		this(fc, id, title, null, null, style != null ? style
 				.getGeoObjectStyle() : null, style != null ? style
 				.getMetaData() : null, null);
@@ -275,7 +275,7 @@
 	/**
 	 * Returns the meta data needed for displaying a legend.
 	 */
-	public Map<Integer, AttributeMetaData> getAttributeMetaDataMap() {
+	public AttributeMetadataMap getAttributeMetaDataMap() {
 		return attrMetaData;
 	}
 
@@ -288,7 +288,7 @@
 	 *            map of attribute meta data
 	 */
 	public void setAttributeMetaData(
-			Map<Integer, AttributeMetaData> attrMetaData) {
+			AttributeMetadataMap attrMetaData) {
 		this.attrMetaData = (attrMetaData != null) ? attrMetaData
 				: createDefaultAttributeMetaDataMap(geoObject);
 	}
@@ -300,9 +300,9 @@
 	 * @param fc
 	 *            a {@link FeatureCollection}
 	 */
-	public static Map<Integer, AttributeMetaData> createDefaultAttributeMetaDataMap(
+	public static AttributeMetadataMap createDefaultAttributeMetaDataMap(
 			FeatureCollection<SimpleFeatureType,SimpleFeature> fc) {
-		HashMap<Integer, AttributeMetaData> metaDataMap = new HashMap<Integer, AttributeMetaData>();
+		AttributeMetadataMap metaDataMap = new AttributeMetadataMap();
 		SimpleFeatureType ftype = fc.getSchema();
 		for (int i = 0; i < ftype.getAttributeCount(); i++) {
 			AttributeDescriptor aType = ftype.getAttributeDescriptors().get(i);

Modified: branches/1.0-gt2-2.6/src/skrueger/geotools/StyledFeaturesInterface.java
===================================================================
--- branches/1.0-gt2-2.6/src/skrueger/geotools/StyledFeaturesInterface.java	2009-09-30 15:36:39 UTC (rev 419)
+++ branches/1.0-gt2-2.6/src/skrueger/geotools/StyledFeaturesInterface.java	2009-10-01 20:22:48 UTC (rev 420)
@@ -29,15 +29,11 @@
  ******************************************************************************/
 package skrueger.geotools;
 
-import java.util.Map;
-
 import org.geotools.data.FeatureSource;
 import org.geotools.feature.FeatureCollection;
 import org.opengis.feature.simple.SimpleFeature;
 import org.opengis.feature.simple.SimpleFeatureType;
 
-import skrueger.AttributeMetaData;
-
 /**
  * This Interface combines all styled layers that are running on
  * {@link FeatureCollection} or {@link FeatureSource}
@@ -49,7 +45,7 @@
  */
 public interface StyledFeaturesInterface<T> extends StyledLayerInterface<T> {
 
-	public abstract Map<Integer, AttributeMetaData> getAttributeMetaDataMap();
+	public abstract AttributeMetadataMap getAttributeMetaDataMap();
 
 	/**
 	 * @return The features of this layer as a {@link FeatureSource}.

Modified: branches/1.0-gt2-2.6/src/skrueger/geotools/StyledLayerUtil.java
===================================================================
--- branches/1.0-gt2-2.6/src/skrueger/geotools/StyledLayerUtil.java	2009-09-30 15:36:39 UTC (rev 419)
+++ branches/1.0-gt2-2.6/src/skrueger/geotools/StyledLayerUtil.java	2009-10-01 20:22:48 UTC (rev 420)
@@ -44,11 +44,8 @@
 import java.io.FileWriter;
 import java.net.URL;
 import java.text.DecimalFormat;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.SortedMap;
-import java.util.TreeMap;
 
 import javax.swing.BorderFactory;
 import javax.swing.Box;
@@ -63,7 +60,6 @@
 import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
 import org.geotools.coverage.grid.io.AbstractGridFormat;
 import org.geotools.feature.FeatureCollection;
-import org.geotools.gce.imagepyramid.ImagePyramidReader;
 import org.geotools.geometry.jts.ReferencedEnvelope;
 import org.geotools.map.DefaultMapLayer;
 import org.geotools.map.MapLayer;
@@ -79,10 +75,12 @@
 import org.jdom.Element;
 import org.jdom.input.SAXBuilder;
 import org.jdom.output.XMLOutputter;
+import org.opengis.feature.simple.SimpleFeature;
 import org.opengis.feature.simple.SimpleFeatureType;
 import org.opengis.parameter.GeneralParameterValue;
 
 import schmitzm.geotools.JTSUtil;
+import schmitzm.geotools.feature.FeatureUtil;
 import schmitzm.geotools.styling.StylingUtil;
 import schmitzm.io.IOUtil;
 import schmitzm.lang.LangUtil;
@@ -244,9 +242,9 @@
 	 *            indicated whether the visible or invisible entries are
 	 *            returned
 	 */
-	public static SortedMap<Integer, AttributeMetaData> getVisibleAttributeMetaData(
+	public static AttributeMetadataMap getVisibleAttributeMetaData(
 			Map<Integer, AttributeMetaData> amdMap, boolean visible) {
-		SortedMap<Integer, AttributeMetaData> filteredMap = new TreeMap<Integer, AttributeMetaData>();
+		AttributeMetadataMap filteredMap = new AttributeMetadataMap();
 		for (AttributeMetaData amd : amdMap.values())
 			if (amd.isVisible())
 				filteredMap.put(amd.getColIdx(), amd);
@@ -289,9 +287,9 @@
 	 * @param element
 	 *            {@link Element} to parse
 	 */
-	public static Map<Integer, AttributeMetaData> parseAttributeMetaDataMap(
+	public static AttributeMetadataMap parseAttributeMetaDataMap(
 			final Element element) {
-		HashMap<Integer, AttributeMetaData> metaData = new HashMap<Integer, AttributeMetaData>();
+		AttributeMetadataMap metaData = new AttributeMetadataMap();
 		List<Element> attributesElements = element
 				.getChildren(ELEM_NAME_ATTRIBUTE);
 		for (Element attibuteElement : attributesElements) {
@@ -308,7 +306,7 @@
 	 *            {@link URL} to parse
 	 * @see #parseAttributeMetaData(Element)
 	 */
-	public static Map<Integer, AttributeMetaData> loadAttributeMetaDataMap(
+	public static AttributeMetadataMap loadAttributeMetaDataMap(
 			final URL documentUrl) throws Exception {
 		Document document = SAX_BUILDER.build(documentUrl);
 		return parseAttributeMetaDataMap(document.getRootElement());
@@ -342,7 +340,7 @@
 	 *            map of attribute meta data
 	 */
 	public static Element createAttributeMetaDataMapElement(
-			final Map<Integer, AttributeMetaData> amdMap) {
+			final AttributeMetadataMap amdMap) {
 		final Element element = new Element(ELEM_NAME_AMD, AMLURI);
 		for (AttributeMetaData amd : amdMap.values())
 			element.addContent(createAttributeMetaDataElement(amd));
@@ -358,7 +356,7 @@
 	 *            {@link URL} to store the XML
 	 */
 	public static void saveAttributeMetaDataMap(
-			final Map<Integer, AttributeMetaData> amdMap, final URL documentUrl)
+			final AttributeMetadataMap amdMap, final URL documentUrl)
 			throws Exception {
 		// Create XML-Document
 		final FileWriter out = new FileWriter(new File(documentUrl.toURI()));
@@ -625,9 +623,9 @@
 		}
 		if (styledObject instanceof StyledFeatureCollectionInterface
 				&& (style.getMetaData() instanceof Map || style.getMetaData() == null)) {
-			Map<Integer, AttributeMetaData> sourceAmd = (Map<Integer, AttributeMetaData>) style
+			AttributeMetadataMap sourceAmd = (AttributeMetadataMap) style
 					.getMetaData();
-			Map<Integer, AttributeMetaData> destAmd = ((StyledFeatureCollectionInterface) styledObject)
+			AttributeMetadataMap destAmd = ((StyledFeatureCollectionInterface) styledObject)
 					.getAttributeMetaDataMap();
 			if (destAmd != null && sourceAmd != null) {
 				destAmd.clear();
@@ -853,7 +851,7 @@
 				// KOMPILIERBAR!!
 			} else if (metaData instanceof Map) {
 				saveAttributeMetaDataMap(
-						(Map<Integer, AttributeMetaData>) metaData, IOUtil
+						(AttributeMetadataMap) metaData, IOUtil
 								.changeUrlExt(geoObjectURL, mdExt));
 			} else
 				throw new UnsupportedOperationException(
@@ -1109,7 +1107,8 @@
 					graphics.setColor(color);
 					graphics.fillRect(0, 0, ICON_SIZE.width, ICON_SIZE.height);
 				} catch (Exception e) {
-					LOGGER.debug("Dann nehmen wir halt den GridCoverageRenderer", e);
+					LOGGER.debug(
+							"Dann nehmen wir halt den GridCoverageRenderer", e);
 					colorModel = null;
 				}
 			}
@@ -1188,6 +1187,7 @@
 	 * Extracts the {@link ColorModel} of any {@link StyledRasterInterface}. May
 	 * return <code>null</code> if the geoobject can not be accessed.
 	 */
+	@SuppressWarnings("unchecked")
 	public static ColorModel getColorModel(StyledRasterInterface<?> styledGrid) {
 		ColorModel colorModel = null;
 		try {
@@ -1204,15 +1204,18 @@
 						styledGrid.getEnvelope(), styledGrid.getCrs());
 
 				readGG.setValue(new GridGeometry2D(new GeneralGridEnvelope(
-						new Rectangle(0, 0, 10, 10)), mapExtend));
+						new Rectangle(0, 0, 1, 1)), mapExtend));
 
-				final AbstractGridCoverage2DReader aReader = (AbstractGridCoverage2DReader) geoObject;
+				FeatureCollection<SimpleFeatureType, SimpleFeature> rFc = (FeatureCollection<SimpleFeatureType, SimpleFeature>) geoObject;
+
+				final AbstractGridCoverage2DReader aReader = (AbstractGridCoverage2DReader) FeatureUtil
+						.getWrappedGeoObject(rFc);
 				GridCoverage2D cov = (GridCoverage2D) aReader
 						.read(new GeneralParameterValue[] { readGG });
 				colorModel = cov.getRenderedImage().getColorModel();
 			}
 		} catch (Exception e) {
-			LOGGER.error("Error reading the colormodel from " + styledGrid);
+			LOGGER.error("Error reading the colormodel from " + styledGrid, e);
 			return null;
 		}
 		return colorModel;

Modified: branches/1.0-gt2-2.6/src/skrueger/i8n/Translation.java
===================================================================
--- branches/1.0-gt2-2.6/src/skrueger/i8n/Translation.java	2009-09-30 15:36:39 UTC (rev 419)
+++ branches/1.0-gt2-2.6/src/skrueger/i8n/Translation.java	2009-10-01 20:22:48 UTC (rev 420)
@@ -44,6 +44,8 @@
 import org.apache.log4j.Logger;
 import org.opengis.util.InternationalString;
 
+import skrueger.geotools.Copyable;
+
 /**
  * Represents a {@link HashMap} of translations. toString() returns the
  * appropriate translation
@@ -52,7 +54,7 @@
  *         Kr&uuml;ger</a>
  */
 
-public class Translation extends HashMap<String, String> {
+public class Translation extends HashMap<String, String> implements Copyable<Translation>{
 	public static final String LOCALECHANGE_PROPERTY = "localechange";
 	public static final String NO_TRANSLATION = "NO TRANSLATION";
 	public static final String DEFAULT_KEY = "default";
@@ -79,7 +81,8 @@
 	 * fromOneLine()
 	 */
 	public Translation clone() {
-		return (Translation) super.clone();
+		throw new RuntimeException("use copy()");
+//		return (Translation) super.clone();
 	}
 
 	/**
@@ -192,8 +195,11 @@
 	 * @author Stefan Alfons Krüger
 	 */
 	public void fromOneLine(final String oneLineCoded) {
+
 		clear();
 		
+		try {
+			
 		if ((oneLineCoded == null) || (oneLineCoded.equals(""))) {
 			put(DEFAULT_KEY, "");
 			return;
@@ -217,6 +223,10 @@
 			put(key, value);
 			eatUp = eatUp.substring(eatUp.indexOf("}") + 1);
 		}
+		} catch (Exception e) {
+			log.warn("Error while reading the oneLineCode '"+oneLineCoded+"'", e);
+			log.warn("Translation will be empty!");
+		}
 	}
 
 	/**
@@ -253,7 +263,6 @@
 		// MS:
 		else {
 			if (get(DEFAULT_KEY) != null) {
-				// log.debug("default lang returned, cuz the translation to "+activeLang+" was not found. Schmeiss raus martin, wenn du das mit der default trans geklärt hast.");
 				return get(DEFAULT_KEY);
 			}
 
@@ -268,21 +277,6 @@
 		return NO_TRANSLATION;
 	}
 
-	/**
-	 * Copy this {@link Translation} to another {@link Translation} e.g. for
-	 * editing
-	 * 
-	 * @return the destination {@link Translation}
-	 */
-	public Translation copy(Translation backup) {
-		if (backup == null)
-			throw new IllegalArgumentException(
-					"Target translation may not be null.");
-		for (String s : keySet()) {
-			backup.put(s, get(s));
-		}
-		return backup;
-	}
 
 	/**
 	 * {@link PropertyChangeListener} can be registered to be informed when the
@@ -339,5 +333,46 @@
 			fromOneLine((String)null);
 	}
 	
+	/**
+	 * Copy this {@link Translation} to another {@link Translation} e.g. for
+	 * editing
+	 * 
+	 * @return the destination {@link Translation}
+	 */
+	@Override
+	public Translation copyTo(Translation translation2) {
+		
+		if (translation2 == null)
+			throw new IllegalArgumentException(
+					"Target translation may not be null.");
+		for (String s : keySet()) {
+			translation2.put(s, get(s));
+		}
+		
+		return translation2;
+	}
 	
+
+	@Override
+	public Translation copy() {
+		return copyTo(new Translation());
+	}
+
+	/**
+	 * Checks if the {@link String}s stored in the {@link Translation} are all valid.
+	 * @return <code>true</code> if all good
+	 */
+	public static boolean checkValid(Translation translationToCheck) {
+		
+		for (String l : translationToCheck.values()) {
+			
+			if (l.contains("{") || l.contains("}")) {
+		
+				return false;
+			}
+		}
+		return true;
+	}
+	
+	
 }

Added: branches/1.0-gt2-2.6/src/skrueger/swing/Cancellable.java
===================================================================
--- branches/1.0-gt2-2.6/src/skrueger/swing/Cancellable.java	2009-09-30 15:36:39 UTC (rev 419)
+++ branches/1.0-gt2-2.6/src/skrueger/swing/Cancellable.java	2009-10-01 20:22:48 UTC (rev 420)
@@ -0,0 +1,10 @@
+package skrueger.swing;
+
+public interface Cancellable {
+
+	/**
+	 * Will revert any changes made to the object.
+	 */
+	public void cancel() ;
+	
+}


Property changes on: branches/1.0-gt2-2.6/src/skrueger/swing/Cancellable.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Id URL
Name: svn:eol-style
   + native

Added: branches/1.0-gt2-2.6/src/skrueger/swing/CancellableDialog.java
===================================================================
--- branches/1.0-gt2-2.6/src/skrueger/swing/CancellableDialog.java	2009-09-30 15:36:39 UTC (rev 419)
+++ branches/1.0-gt2-2.6/src/skrueger/swing/CancellableDialog.java	2009-10-01 20:22:48 UTC (rev 420)
@@ -0,0 +1,9 @@
+package skrueger.swing;
+
+public interface CancellableDialog extends Cancellable {
+
+	public boolean isCancelled();
+
+	void cancelClose();
+	
+}


Property changes on: branches/1.0-gt2-2.6/src/skrueger/swing/CancellableDialog.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Id URL
Name: svn:eol-style
   + native

Added: branches/1.0-gt2-2.6/src/skrueger/swing/CancellableDialogAdapter.java
===================================================================
--- branches/1.0-gt2-2.6/src/skrueger/swing/CancellableDialogAdapter.java	2009-09-30 15:36:39 UTC (rev 419)
+++ branches/1.0-gt2-2.6/src/skrueger/swing/CancellableDialogAdapter.java	2009-10-01 20:22:48 UTC (rev 420)
@@ -0,0 +1,70 @@
+package skrueger.swing;
+
+import java.awt.Window;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+import javax.swing.JDialog;
+import javax.swing.JOptionPane;
+
+public abstract class CancellableDialogAdapter extends JDialog implements
+		CancellableDialog {
+
+	protected boolean cancelled = false;
+
+	@Override
+	public boolean isCancelled() {
+		return cancelled;
+	}
+
+	public CancellableDialogAdapter(final Window parentWindow) {
+		super(parentWindow);
+		initDialog();
+	}
+
+	private void initDialog() {
+
+		setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
+
+		addWindowListener(new WindowAdapter() {
+
+			@Override
+			public void windowClosing(WindowEvent e) {
+				setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
+				
+				int showConfirmDialog = JOptionPane.showConfirmDialog(
+						CancellableDialogAdapter.this, "Speichern?",
+						"Änderungen speichern?", JOptionPane.YES_NO_CANCEL_OPTION); // i8n
+
+				if (showConfirmDialog == JOptionPane.YES_OPTION)
+					okClose();
+				else if (showConfirmDialog == JOptionPane.NO_OPTION)
+					cancelClose();
+			}
+
+		});
+	}
+
+	public CancellableDialogAdapter(final Window parentWindow, String title) {
+		super(parentWindow, title);
+		initDialog();
+	}
+
+	@Override
+	public void cancelClose() {
+		cancel();
+		dispose();
+	}
+
+	@Override
+	public abstract void cancel();
+
+	/**
+	 * This method is called when the dialog is closed and not canceled. Can be
+	 * overwritten to do anything when the dialog has been accepted. For example
+	 * cheking for any {@link Checkable} components. Returns false, if the ok
+	 * has been vetoed.
+	 */
+	public abstract boolean okClose();
+
+}


Property changes on: branches/1.0-gt2-2.6/src/skrueger/swing/CancellableDialogAdapter.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Id URL
Name: svn:eol-style
   + native

Added: branches/1.0-gt2-2.6/src/skrueger/swing/Checkable.java
===================================================================
--- branches/1.0-gt2-2.6/src/skrueger/swing/Checkable.java	2009-09-30 15:36:39 UTC (rev 419)
+++ branches/1.0-gt2-2.6/src/skrueger/swing/Checkable.java	2009-10-01 20:22:48 UTC (rev 420)
@@ -0,0 +1,7 @@
+package skrueger.swing;
+
+public interface Checkable {
+
+	public boolean checkValidInputs() ;
+	
+}


Property changes on: branches/1.0-gt2-2.6/src/skrueger/swing/Checkable.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Id URL
Name: svn:eol-style
   + native

Added: branches/1.0-gt2-2.6/src/skrueger/swing/DialogManager.java
===================================================================
--- branches/1.0-gt2-2.6/src/skrueger/swing/DialogManager.java	2009-09-30 15:36:39 UTC (rev 419)
+++ branches/1.0-gt2-2.6/src/skrueger/swing/DialogManager.java	2009-10-01 20:22:48 UTC (rev 420)
@@ -0,0 +1,140 @@
+package skrueger.swing;
+
+import java.awt.Component;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.HashMap;
+import java.util.HashSet;
+
+import javax.swing.JDialog;
+
+import org.apache.log4j.Logger;
+
+public abstract class DialogManager<KEY, DIALOG extends JDialog> extends
+		JDialog {
+
+	public abstract class FactoryInterface {
+
+		public abstract DIALOG create();
+
+	}
+
+	final Logger LOGGER = Logger.getLogger(DialogManager.class);
+
+	private HashMap<KEY, DIALOG> dialogCache = new HashMap<KEY, DIALOG>();
+
+	public DialogManager() {
+	}
+
+	/**
+	 * This will be done with every dialog that an instance is required for.
+	 * 
+	 * @param dialog
+	 * @return
+	 */
+	protected DIALOG bringup(DIALOG dialog) {
+		if (!dialog.isVisible())
+			dialog.setVisible(true);
+		dialog.toFront();
+
+		return dialog;
+	}
+
+	public abstract DIALOG getInstanceFor(final KEY key, final Component owner,
+			final Object... constArgs);
+
+	/**
+	 * @return Is there an open/visible dialog for the given layer id?
+	 */
+	public boolean isVisibleFor(KEY key) {
+		return dialogCache.containsKey(key) && dialogCache.get(key).isVisible();
+	}
+
+	/**
+	 * Will dispose any dialog that is registered to the given parent
+	 * {@link Component}
+	 * 
+	 * @param parent
+	 */
+	public void disposeInstanceForParent(final Component parent) {
+
+		final HashMap<KEY, JDialog> clonedHashMap = (HashMap<KEY, JDialog>) dialogCache
+				.clone();
+
+		for (KEY chartId : clonedHashMap.keySet()) {
+			if (dialogCache.get(chartId).getParent() == parent) {
+				disposeInstanceFor(chartId);
+			}
+		}
+	}
+
+	public boolean disposeInstanceFor(KEY chartId) {
+		synchronized (dialogCache) {
+
+			final DIALOG dialog = dialogCache.get(chartId);
+			if (dialog != null) {
+				dialog.dispose();
+				if (dialogCache.remove(chartId) == null) {
+					LOGGER.warn("Hae?!?!"); //TODO cleanup
+				}
+				return true;
+			}
+			return false;
+		}
+	}
+
+	/**
+	 * Checks whether there already is an instance for that key and otherwise
+	 * will create the instance by invoking the {@link FactoryInterface} #create
+	 * method.
+	 * 
+	 * @param key
+	 * @param factory
+	 *            {@link FactoryInterface} that creates the DIALOG
+	 * 
+	 * @return Always a visible and inFront instance for the given key.
+	 */
+	public DIALOG getInstanceFor(final KEY key, FactoryInterface factory) {
+		DIALOG dialog;
+		if (isVisibleFor(key)) {
+			dialog = dialogCache.get(key);
+		} else {
+
+			dialog = factory.create();
+
+			dialogCache.put(key, dialog);
+
+			dialog.addWindowListener(new WindowAdapter() {
+				@Override
+				public void windowClosed(final WindowEvent e) {
+					disposeInstanceFor(key);
+				}
+			});
+		}
+		return dialog;
+	}
+	
+
+	/**
+	 * Disposes all open instances.
+	 * 
+	 * @return <code>true</code> if at least one window has been disposed.
+	 */
+	public boolean disposeAll() {
+		
+		boolean atLeastOne = false;
+		HashSet<KEY> tempKeys = new HashSet<KEY>(dialogCache.keySet());
+		for (KEY key : tempKeys) {
+			DIALOG dialog = dialogCache
+					.get(key);
+			if (dialog != null) {
+				dialog.dispose();
+				atLeastOne = true;
+			}
+		}
+		tempKeys.clear();
+		dialogCache.clear();
+		return atLeastOne;
+	}
+	
+}


Property changes on: branches/1.0-gt2-2.6/src/skrueger/swing/DialogManager.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Id URL
Name: svn:eol-style
   + native

Modified: branches/1.0-gt2-2.6/src/skrueger/swing/TranslationAskJDialog.java
===================================================================
--- branches/1.0-gt2-2.6/src/skrueger/swing/TranslationAskJDialog.java	2009-09-30 15:36:39 UTC (rev 419)
+++ branches/1.0-gt2-2.6/src/skrueger/swing/TranslationAskJDialog.java	2009-10-01 20:22:48 UTC (rev 420)
@@ -41,8 +41,6 @@
 
 import javax.swing.AbstractAction;
 import javax.swing.Action;
-import javax.swing.BorderFactory;
-import javax.swing.Box;
 import javax.swing.JButton;
 import javax.swing.JComponent;
 import javax.swing.JDialog;
@@ -52,11 +50,9 @@
 import javax.swing.KeyStroke;
 
 import schmitzm.swing.SwingUtil;
-import skrueger.i8n.Translation;
 
-public class TranslationAskJDialog extends JDialog {
+public class TranslationAskJDialog extends CancellableDialogAdapter{
 
-	private String[] backup = new String[50]; // Maximum 50 languages ;-)
 	private OkButton okButton;
 	private CancelButton cancelButton;
 
@@ -68,6 +64,7 @@
 	private boolean hasBeenCanceled;
 
 	private JButton[] optionalButtons;
+	private TranslationsAskJPanel translationsAskPane;
 
 	/**
 	 * Since the registerKeyboardAction() method is part of the JComponent class
@@ -143,30 +140,10 @@
 	public void setComponents(final JComponent... translationEditJPanels) {
 		this.translationEditJPanelsOrJustComponents = translationEditJPanels;
 
-		backup();
-
 		init();
 	}
 
-	/**
-	 * Stores the original values of all {@link TranslationEditJPanel}s so
-	 * cancel works.
-	 */
-	protected void backup() {
-		// Remember backups for all the TranslationEditJPanel
-		int count = 0;
-		for (JComponent component : translationEditJPanelsOrJustComponents) {
-			if (component instanceof TranslationEditJPanel) {
-				TranslationEditJPanel tep = (TranslationEditJPanel) component;
-				Translation orig = tep.getTranslation();
 
-				// We don't want to overwrite the Translation object on
-				// restore(). We just want to change its value.
-				backup[count++] = orig.toOneLine();
-			}
-		}
-	}
-
 	private void init() {
 		setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
 		addWindowListener(new WindowAdapter() {
@@ -176,25 +153,20 @@
 			}
 
 		});
-		SwingUtil.centerFrameOnScreen(this);
-		Box box = Box.createVerticalBox();
-		for (JComponent panel : translationEditJPanelsOrJustComponents) {
-			panel.setAlignmentX(java.awt.Component.LEFT_ALIGNMENT);
-			panel.setBorder(BorderFactory.createEmptyBorder(5, 6, 5, 6));
-			box.add(panel);
-
-		}
+		
+		translationsAskPane = new TranslationsAskJPanel(translationEditJPanelsOrJustComponents);
 		JPanel cp = new JPanel(new BorderLayout());
-		cp.add(box, BorderLayout.WEST);
+		cp.add(translationsAskPane, BorderLayout.WEST);
 		cp.add(getButtons(), BorderLayout.SOUTH);
 		setContentPane(cp);
 
 		setTitle(SwingUtil.R("TranslationAskJDialog.Title"));
 		setModal(true);
 		pack();
+		SwingUtil.centerFrameOnScreen(this);
 	}
 
-	public void setButtons(JButton... optionalButtons) {
+	public void setOptionalButtons(JButton... optionalButtons) {
 		this.optionalButtons = optionalButtons;
 		init();
 	}
@@ -204,26 +176,15 @@
 	 * overwriting this method, call super.cancel() after restoring your
 	 * properties.
 	 */
+	@Override
 	public void cancel() {
-		restore();
+		translationsAskPane.cancel();
 		firePropertyChange(PROPERTY_CANCEL_AND_CLOSE, null, null);
-		setCancelled(true);
+		hasBeenCanceled = true;
 		setVisible(false);
 		dispose();
 	}
 
-	/**
-	 * Used to restore all the values when cancel has been pressed.
-	 */
-	private void restore() {
-		int count = 0;
-		for (JComponent component : translationEditJPanelsOrJustComponents) {
-			if (component instanceof TranslationEditJPanel) {
-				TranslationEditJPanel tep = (TranslationEditJPanel) component;
-				tep.getTranslation().fromOneLine(backup[count++]);
-			}
-		}
-	}
 
 	private JComponent getButtons() {
 		JPanel jPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
@@ -253,12 +214,7 @@
 				}
 
 				public void actionPerformed(ActionEvent evt) {
-					TranslationAskJDialog.this.firePropertyChange(
-							PROPERTY_APPLY_AND_CLOSE, null, null);
 
-					if (!checkValidInputs())
-						return;
-
 					okClose();
 
 				}
@@ -271,12 +227,6 @@
 		if (cancelButton == null) {
 			cancelButton = new CancelButton(new AbstractAction("") {
 				public void actionPerformed(ActionEvent evt) {
-					// restore();
-					// TranslationAskJDialog.this.firePropertyChange(
-					// PROPERTY_CANCEL_AND_CLOSE, null, null);
-					// setVisible(false);
-					// setCancelled(true);
-					// dispose();
 					cancel();
 				}
 			});
@@ -287,48 +237,27 @@
 	}
 
 	/**
-	 * This method is only called when the dialog is closed and not cancelled.
+	 * This method is only called when the dialog is closed and not canceled.
 	 * Can be overwritten to do anything when the dialog has been accepted.
 	 */
-	protected void okClose() {
-		setVisible(false);
-		dispose();
-	}
+	public boolean okClose() {
 
-	/**
-	 * @return <code>true</code> if none of the translations contains illegal
-	 *         characters.
-	 */
-	protected boolean checkValidInputs() {
-
-		for (JComponent component : translationEditJPanelsOrJustComponents) {
-			if (component instanceof TranslationEditJPanel) {
-				TranslationEditJPanel tep = (TranslationEditJPanel) component;
-
-				for (String l : tep.getTranslation().values()) {
-					if (l.contains("{") || l.contains("}")) {
-						JOptionPane
-								.showMessageDialog(
-										this,
-										SwingUtil
-												.R("TranslationAskJDialog.ErrorMsg.InvalidCharacterInTranslation"));
-						return false;
-					}
-				}
-
-			}
-		}
-
+		if (!translationsAskPane.checkValidInputs())
+			return false;
+		
+		
+		dispose();
+		
+		TranslationAskJDialog.this.firePropertyChange(
+				PROPERTY_APPLY_AND_CLOSE, null, null);
 		return true;
 	}
 
-	private void setCancelled(boolean hasBeenCanceled) {
-		this.hasBeenCanceled = hasBeenCanceled;
-	}
 
+
 	/**
 	 * After the modal dialog has been closed, this allows to find out, whether
-	 * the dialog has been canceled.
+	 * the {@link Component} has been canceled.
 	 * 
 	 * @return <code>true</code> if the {@link JDialog} has been canceled.
 	 */

Added: branches/1.0-gt2-2.6/src/skrueger/swing/TranslationsAskJPanel.java
===================================================================
--- branches/1.0-gt2-2.6/src/skrueger/swing/TranslationsAskJPanel.java	2009-09-30 15:36:39 UTC (rev 419)
+++ branches/1.0-gt2-2.6/src/skrueger/swing/TranslationsAskJPanel.java	2009-10-01 20:22:48 UTC (rev 420)
@@ -0,0 +1,102 @@
+package skrueger.swing;
+
+import javax.swing.BorderFactory;
+import javax.swing.JComponent;
+import javax.swing.JOptionPane;
+
+import net.miginfocom.swing.MigLayout;
+import schmitzm.swing.JPanel;
+import schmitzm.swing.SwingUtil;
+import skrueger.i8n.Translation;
+
+public class TranslationsAskJPanel extends JPanel implements Cancellable, Checkable {
+
+	private String[] backup = new String[50]; // Maximum 50 languages
+	private final JComponent[] translationEditJPanelsOrJustComponents;
+
+	public TranslationsAskJPanel(
+			JComponent... translationEditJPanelsOrJustComponents_) {
+		super(new MigLayout("wrap 1, width 100%", "[]"));
+
+		this.translationEditJPanelsOrJustComponents = translationEditJPanelsOrJustComponents_;
+
+		backup();
+
+		// Box box = Box.createVerticalBox();
+		// for (JComponent panel : translationEditJPanelsOrJustComponents) {
+		// panel.setAlignmentX(java.awt.Component.LEFT_ALIGNMENT);
+		// panel.setBorder(BorderFactory.createEmptyBorder(5, 6, 5, 6));
+		// box.add(panel);
+		//
+		// }
+		// add(box);
+
+		for (JComponent panel : translationEditJPanelsOrJustComponents) {
+			panel.setAlignmentX(java.awt.Component.LEFT_ALIGNMENT);
+			panel.setBorder(BorderFactory.createEmptyBorder(5, 6, 5, 6));
+			add(panel);
+		}
+
+	}
+
+	/**
+	 * Stores the original values of all {@link TranslationEditJPanel}s so
+	 * cancel works.
+	 */
+	protected void backup() {
+		// Remember backups for all the TranslationEditJPanel
+		int count = 0;
+		for (JComponent component : translationEditJPanelsOrJustComponents) {
+			if (component instanceof TranslationEditJPanel) {
+				TranslationEditJPanel tep = (TranslationEditJPanel) component;
+				Translation orig = tep.getTranslation();
+
+				// We don't want to overwrite the Translation object on
+				// restore(). We just want to change its value.
+				backup[count++] = orig.toOneLine();
+			}
+		}
+	}
+
+	/**
+	 * Used to restore all the values when cancel has been pressed.
+	 */
+	@Override
+	public void cancel() {
+		int count = 0;
+		for (JComponent component : translationEditJPanelsOrJustComponents) {
+			if (component instanceof TranslationEditJPanel) {
+				TranslationEditJPanel tep = (TranslationEditJPanel) component;
+				tep.getTranslation().fromOneLine(backup[count++]);
+			}
+		}
+	}
+	
+
+	/**
+	 * @return <code>true</code> if none of the translations contains illegal
+	 *         characters.
+	 */
+	public boolean checkValidInputs() {
+
+		for (JComponent component : translationEditJPanelsOrJustComponents) {
+			if (component instanceof TranslationEditJPanel) {
+				TranslationEditJPanel tep = (TranslationEditJPanel) component;
+
+				final Translation translationToCheck = tep.getTranslation();
+				
+				if (!Translation.checkValid(translationToCheck)) {
+					JOptionPane
+					.showMessageDialog(
+							this,
+							SwingUtil
+									.R("TranslationAskJDialog.ErrorMsg.InvalidCharacterInTranslation"));	
+					return false;
+				}
+				
+			}
+		}
+
+		return true;
+	}
+}


Property changes on: branches/1.0-gt2-2.6/src/skrueger/swing/TranslationsAskJPanel.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