private void collectAttributes(
        SimpleFeatureType schema, List<String> retainedAttributes, SimpleFeatureTypeBuilder tb) {
      for (AttributeDescriptor descriptor : schema.getAttributeDescriptors()) {
        // check whether descriptor has been selected in the attribute list
        boolean isInRetainList = true;
        if (retainedAttributes != null) {

          isInRetainList = retainedAttributes.contains(descriptor.getLocalName());
          logger.fine("Checking " + descriptor.getLocalName() + " --> " + isInRetainList);
        }
        if (!isInRetainList || schema.getGeometryDescriptor() == descriptor) {
          continue;
        }

        // build the attribute to return
        AttributeTypeBuilder builder = new AttributeTypeBuilder();
        builder.setName(schema.getName().getLocalPart() + "_" + descriptor.getName());
        builder.setNillable(descriptor.isNillable());
        builder.setBinding(descriptor.getType().getBinding());
        builder.setMinOccurs(descriptor.getMinOccurs());
        builder.setMaxOccurs(descriptor.getMaxOccurs());
        builder.setDefaultValue(descriptor.getDefaultValue());
        builder.setCRS(schema.getCoordinateReferenceSystem());
        AttributeDescriptor intersectionDescriptor =
            builder.buildDescriptor(
                schema.getName().getLocalPart() + "_" + descriptor.getName(), descriptor.getType());
        tb.add(intersectionDescriptor);
        tb.addBinding(descriptor.getType());
      }
    }
  static AttributeDescriptor getIntersectionType(
      SimpleFeatureCollection first, SimpleFeatureCollection second) {
    Class firstGeomType = first.getSchema().getGeometryDescriptor().getType().getBinding();
    Class secondGeomType = second.getSchema().getGeometryDescriptor().getType().getBinding();

    // figure out the output geometry type
    Class binding;
    if (isGeometryTypeIn(secondGeomType, Point.class)) {
      binding = Point.class;
    } else if (isGeometryTypeIn(secondGeomType, MultiPoint.class)) {
      binding = MultiPoint.class;
    } else if (isGeometryTypeIn(secondGeomType, LineString.class, MultiLineString.class)) {
      binding = MultiLineString.class;
    } else if (isGeometryTypeIn(secondGeomType, Polygon.class, MultiPolygon.class)) {
      if (isGeometryTypeIn(firstGeomType, Polygon.class, MultiPolygon.class)) {
        binding = MultiPolygon.class;
      } else {
        binding = MultiLineString.class;
      }
    } else {
      // we can't be more precise than this
      binding = Geometry.class;
    }

    AttributeTypeBuilder builder = new AttributeTypeBuilder();
    builder.setName("the_geom");
    builder.setBinding(binding);
    builder.setCRS(first.features().next().getFeatureType().getCoordinateReferenceSystem());
    AttributeDescriptor descriptor = builder.buildDescriptor("the_geom");
    return descriptor;
  }
  public FeatureTypeUnionBuilder setGeometryClass(
      final String geometryName,
      final Class<? extends Geometry> geomClass,
      final CoordinateReferenceSystem crs) {

    assert geometryName != null : "the geometry name can not be null";
    assert geomClass != null : "the geometry class can not be null";
    assert crs != null : "the CRS can not be null";

    this.geometryName = geometryName;
    this.geometryClass = geomClass;

    GeometryDescriptor geoAttrType;

    AttributeTypeBuilder build = new AttributeTypeBuilder();
    build.setName(this.geometryName);
    build.setBinding(this.geometryClass);
    build.setNillable(true);
    build.setLength(100);
    build.setCRS(crs);

    GeometryType type = build.buildGeometryType();
    geoAttrType = build.buildDescriptor(this.geometryName, type);

    this.unionGeometryAttr = geoAttrType;

    return this;
  }
  /**
   * Adds a new geometric attribute w/ provided name, class, and coordinate reference system.
   *
   * <p>The <tt>crs</tt> parameter may be <code>null</code>.
   *
   * @param name The name of the attribute.
   * @param binding The class that the attribute is bound to.
   * @param crs The crs of of the geometry, may be <code>null</code>.
   */
  public void add(String name, Class<?> binding, CoordinateReferenceSystem crs) {
    attributeBuilder.setBinding(binding);
    attributeBuilder.setName(name);
    attributeBuilder.setCRS(crs);

    GeometryType type = attributeBuilder.buildGeometryType();
    GeometryDescriptor descriptor = attributeBuilder.buildDescriptor(name, type);
    attributes().add(descriptor);
  }
  @Test
  public void testCreateBasedOnShapeType() throws Exception {
    TestEditBlackboard bb = new TestEditBlackboard();
    String fid = "FeatureID";
    EditGeom geom = bb.newGeom(fid, null);
    bb.addPoint(10, 10, geom.getShell());
    EditGeom geom2 = bb.newGeom(fid, null);
    AttributeTypeBuilder builder = new AttributeTypeBuilder();
    builder.setBinding(Geometry.class);
    builder.setName("geom");
    GeometryDescriptor at = builder.buildDescriptor("geom", builder.buildGeometryType());
    bb.addPoint(100, 100, geom2.getShell());

    String fid2 = "FID2";
    EditGeom differentGeom = bb.newGeom(fid2, null);
    bb.addPoint(200, 200, differentGeom.getShell());

    Map<String, Bag> result = GeometryCreationUtil.createAllGeoms(geom, Point.class, at, false);
    assertEquals(1, result.get(fid2).jts.size());
    assertEquals(Point.class, result.get(fid2).jts.get(0).getClass());

    differentGeom.setShapeType(ShapeType.LINE);
    result = GeometryCreationUtil.createAllGeoms(geom, Point.class, at, false);
    assertEquals(1, result.get(fid2).jts.size());
    assertEquals(LineString.class, result.get(fid2).jts.get(0).getClass());

    differentGeom.setShapeType(ShapeType.POLYGON);
    result = GeometryCreationUtil.createAllGeoms(geom, Point.class, at, false);
    assertEquals(1, result.get(fid2).jts.size());
    assertEquals(Polygon.class, result.get(fid2).jts.get(0).getClass());

    differentGeom.setShapeType(ShapeType.UNKNOWN);
    result = GeometryCreationUtil.createAllGeoms(geom, Point.class, at, false);
    assertEquals(1, result.get(fid2).jts.size());
    assertEquals(Point.class, result.get(fid2).jts.get(0).getClass());

    bb.addPoint(200, 200, differentGeom.getShell());

    result = GeometryCreationUtil.createAllGeoms(geom, Point.class, at, false);
    assertEquals(1, result.get(fid2).jts.size());
    assertEquals(Point.class, result.get(fid2).jts.get(0).getClass());

    bb.addPoint(200, 210, differentGeom.getShell());

    result = GeometryCreationUtil.createAllGeoms(geom, Point.class, at, false);
    assertEquals(1, result.get(fid2).jts.size());
    assertEquals(LineString.class, result.get(fid2).jts.get(0).getClass());

    bb.addPoint(200, 200, differentGeom.getShell());

    result = GeometryCreationUtil.createAllGeoms(geom, Point.class, at, false);
    assertEquals(1, result.get(fid2).jts.size());
    assertEquals(Polygon.class, result.get(fid2).jts.get(0).getClass());
  }
  /**
   * Adds a new attribute w/ provided name and class.
   *
   * <p>The provided class is used to locate an attribute type binding previously specified by
   * {@link #addBinding(AttributeType)},{@link #addBindings(Schema)}, or {@link
   * #setBindings(Schema)}.
   *
   * <p>If not such binding exists then an attribute type is created on the fly.
   *
   * @param name The name of the attribute.
   * @param bind The class the attribute is bound to.
   */
  public void add(String name, Class<?> binding) {

    AttributeDescriptor descriptor = null;

    attributeBuilder.setBinding(binding);
    attributeBuilder.setName(name);

    // check if this is the name of the default geometry, in that case we
    // better make it a geometry type
    // also check for jts geometry, if we ever actually get to a point where a
    // feature can be backed by another geometry model (like iso), we need
    // to remove this check
    //
    if ((defaultGeometry != null && defaultGeometry.equals(name))
        || Geometry.class.isAssignableFrom(binding)) {

      // if no crs was set, set to defaultCRS
      if (!attributeBuilder.isCRSSet()) {
        if (defaultCrs == null && !defaultCrsSet) {
          LOGGER.fine(
              "Creating "
                  + name
                  + " with null CoordinateReferenceSystem - did you mean to setCRS?");
        }
        attributeBuilder.setCRS(defaultCrs);
      }

      GeometryType type = attributeBuilder.buildGeometryType();
      descriptor = attributeBuilder.buildDescriptor(name, type);
    } else {
      AttributeType type = attributeBuilder.buildType();
      descriptor = attributeBuilder.buildDescriptor(name, type);
    }

    attributes().add(descriptor);
  }