Feature Instantiation

This describes the LineFeature because it is more complicated, but much of this discussion will be applicable to Node Features as well.

Use Cases

In general, we want to avoid collisions between assigned IDs and any new IDs. By keeping a permanent record of the last assigned ID, and then using that to hand out new IDs, we can avoid collisions across all instances.

Unfortunately, this sets up a situation where any of the Feature Implementations will depend on a service that can obtain and maintain that ID. Dependency Injection is probably the way to go. Supply a particular service to supply IDs in the case we don't have a Store and a different service in the case where we are using the store.

Create Feature from External Source

Example is reading in a Track where there is a name, URL, and a LineString geometry available for the constructor.

NetworkStore would be available for supplying the ID service.

  • One approach is to build a TrackImpl with the displayName and URL, and then use the Feature constructor to assemble the TrackFeature from the Track and the LineString. This follows the pattern of merging the Domain-specific data with the Geometry appropriate to the feature.
  • In this case, the ID would be assigned at the time the instance is created based on what other values have already been loaded from the permanent store.

Create Feature from Permanent Store

NetworkStore would be available for supplying the ID directly via the SimpleFeature. The value passed will have come directly from the permanent store.

Create Feature from hand-entered data

In general, the NetworkStore would not be available. Fall back to the memory-based IDs.

Steps

  1. Create a LineString.
  2. Pass it to a constructor or factory that instantiates the LineFeature.

Domain specific knowledge is inconsequential for the most part (except to verify that it moves around correctly).

Create Feature from programatically derived data

If the NetworkStore is available, this will be used. In testing, it is less likely the NetworkStore would be brought up and the memory-based IDs would fulfill the contract.

Steps

This is the most complex of the Use Cases. As a first cut, let's look at what it takes to bring in an Edge from permanent storage, and then split it into two new Edges for updating the Network.

  1. Read in a SimpleFeature(Impl)
  2. Pass this to a Constructor which accepts SimpleFeature with the understanding that all data is present to populate our internal representation. Let's assume that we're bringing in an Unrated Segment and not a rated one for simplicity.
  3. Later on, the user finds an intersection with a new Track that will require splitting this Edge at one of the internal Nodes (Point geometry underneath).
  4. The two new Edges will each get a new ID and the remaining domain-specific features will be copied from the original.

Proposed Design

  • Inside the geotools package, there will be a simple service that returns a sequence of unique IDs which is memory-based.
  • Inside the crMain package — which holds the NetworkStore class — there will be a service that bases its sequence on reading the permanent store and avoiding the use of those IDs.
  • The constructors for Domain implementations will be configured to use one of the two services — or any other service for that matter — for obtaining new IDs.

Constraints

  • The ID will be unique across all LineFeature implementations. This includes both those with and those without a Geometry. This means the ID will be carried by a TrackImpl and must be checked against any values that make it into the SimpleFeatureImpl that is part of a Feature.

Alternative

  • It may make more sense to assign both the Domain-specific data and the Geometry data their own IDs and to map between the two within the Feature Implementations (as the underlying SimpleFeatureImpl is able to support).

Temporary Backdoor

In the geotools package, when I was bootstrapping the first network, I had a spot where it sort of made sense to instantiate some Feature Impls by passing an ID. I worked around the limitation I had — no SimpleFeatureImpl just yet — by new'ing up a subclass where the setId was exposed. Although the member variable was private, there was nothing that prevented me from creating my own implementation of the interface that also happened to allow setting the ID. That class is called TempSegmentImpl.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License