Motivation:

Insert features using existing FIDs

Contact:

Andrea Aime

Tracker:

http://jira.codehaus.org/browse/GEOT-3120

Tagline:

Insert using existing FIDs

Description

GeoTools data stores always generate a new feature id when a new feature is being inserted. In some cases this is a requirement, such as in Shapefiles, where the id is the feature row number in the file. In other cases it's merely an implementation choice, such as the case of property data store or the JDBC data stores.

Using the user provided feature id is a requirement in a few cases:

This proposal adds hints to allow:

To support advertisement QueryCapabilities gets a new method:

public class QueryCapabilities {

    /**
     * If true the datastore supports using the provided feature id in the data insertion
     * workflow as opposed to generating a new id. In that case it will look into the user data
     * map ({@link Feature#getUserData()}) for a {@link Hints#USE_EXISTING_FID} key associated to a
     * {@link Boolean#TRUE} value, if the key/value pair is there an attempt to use the provided
     * id will be made, and the operation will fail of the key cannot be parsed into a valid
     * storage identifier.
     * @return
     */
    public boolean isUseExisingFIDSupported() {
        return false;
    }
}

To support uses in asking the FID to be used a new well know hint has been added, that need to be specified in the Feature user map (see example below):

pubilc class Hints {
 ...

    /**
     * When this key is used in the user data section of a feature and the feature store
     * query capabilities reports being able to use provided feature ids the store will
     * try to use the provided feature id during insertion, and will fail if the FID
     * cannot be parsed into a valid storage identifier
     *
     * @since 2.7
     */
    public static final Key USE_EXISTING_FID = new Key("org.geotools.fidPolicy.UseExisting");


}

Implementation wise the JDBC data stores and the property data store will be modified to support the USE_EXISTING_FID hint.

GEOT-3120 contains a full working patch to implement the above.

Status

This proposal has been implemented

Voting has not started yet:

Usage example

AFTER

The following unit tests shows checking for USE_EXISTING_FID hint support and asking the FID to be used during insertion.

public void testAddFeaturesUseExisting() throws IOException {
    // check we advertise the ability to reuse feature ids
    assertTrue(featureStore.getQueryCapabilities().isUseExisingFIDSupported());

    SimpleFeatureBuilder b = new SimpleFeatureBuilder(featureStore.getSchema());
    DefaultFeatureCollection collection = new DefaultFeatureCollection(null,
            featureStore.getSchema());

    String typeName = b.getFeatureType().getTypeName();
    for (int i = 3; i < 6; i++) {
        b.set(aname("intProperty"), new Integer(i));
        b.set(aname("geometry"), new GeometryFactory().createPoint(new Coordinate(i, i)));
        b.featureUserData(Hints.USE_EXISTING_FID, Boolean.TRUE);
        collection.add(b.buildFeature(typeName + "." + (i * 10)));
    }
    List<FeatureId> fids = featureStore.addFeatures(collection);

    assertEquals(3, fids.size());

    // check the created ids are the ones expected
    assertTrue(fids.contains(SimpleFeatureBuilder.createDefaultFeatureIdentifier(typeName + ".30")));
    assertTrue(fids.contains(SimpleFeatureBuilder.createDefaultFeatureIdentifier(typeName + ".40")));
    aassertTrue(fids.contains(SimpleFeatureBuilder.createDefaultFeatureIdentifier(typeName + ".50")));

    SimpleFeatureCollection features = featureStore.getFeatures();
    assertEquals(6, features.size());

    FilterFactory ff = dataStore.getFilterFactory();

    // manually check features are actually there
    for (Iterator f = fids.iterator(); f.hasNext();) {
        FeatureId identifier = (FeatureId) f.next();
        String fid = identifier.getID();
        Id filter = ff.id(Collections.singleton(identifier));

        features = featureStore.getFeatures(filter);
        assertEquals(1, features.size());
    }
}

Documentation Changes

The following page already documents the above (as modified by Jody):